PDA

View Full Version : Normal Maps -> MipMapping



Diapolo
11-12-2002, 08:14 AM
Hi,

I guess I know the answer to my question, but I would like to hear it from an advanced OGL coder http://www.opengl.org/discussion_boards/ubb/smile.gif.

If I use GL_LINEAR_MIPMAP_LINEAR for a Normalmap, that I use for DOT-3 Lighting, the generated Mipmaps (via GL_SGIS_generate_mipmap) will contain denormalized normals, or?

I would have to implement a function, that creates the Mipmaps and correctly normalizes the Normals in the Normalmap, right?

Regards,
Diapolo

Zeno
11-12-2002, 08:36 AM
Yep, it's more correct if you renormalize each pixel in the mipmaps of your normalmap. This is something that most minification filters won't do for you.

You'll also lose normalization when doing linear interpolation (both within a single level and between mipmaps) so you may have to renormalize with a cubemap or something at the end anyway.

-- Zeno

zed
11-12-2002, 09:25 AM
yes u will need to regenerate the renormalized normals yourself for the smaller mipmaps SGIS_mipmap or gluBuodmipmaps DONT do it.
also u might wanna rescale the heights by 2 for each smaller miopmap

Diapolo
11-12-2002, 10:47 AM
Thanks for your replies http://www.opengl.org/discussion_boards/ubb/smile.gif.

Could denormalized Normals in the Mipmap of a Normalmap lead to color banding effects during Dot-3 Lighting?

Diapolo

Btw.: I was thinking about a good way to do texture loading, but Im not sure how to do it good. I created a C++ class, that receives all needed parameters via the constructor and then loads the texture into OGL. You can query for the texture ID via an method of that class, but Im absolutely not satisfied with that approach (needs global variables). I would like to be more "modular". Any hints for me http://www.opengl.org/discussion_boards/ubb/wink.gif?

pkaler
11-12-2002, 10:57 AM
Originally posted by Diapolo:

Btw.: I was thinking about a good way to do texture loading, but Im not sure how to do it good. I created a C++ class, that receives all needed parameters via the constructor and then loads the texture into OGL. You can query for the texture ID via an method of that class, but Im absolutely not satisfied with that approach (needs global variables). I would like to be more "modular". Any hints for me http://www.opengl.org/discussion_boards/ubb/wink.gif?

Think about interfaces. Have a abstract base Texture class that defines an interface. Then derive Cubemap, Mipmap, NormalMap, Diffusemap, etc classes from your Texture class.
Next, have an abstract TextureFactory class and then derive classes for building textures on top of that.

Diapolo
11-12-2002, 11:07 AM
I should explain a bit further http://www.opengl.org/discussion_boards/ubb/smile.gif.

The class I have receives MANY parameters, Path, Texture size, Texture Type, Filtering Mode, Wrapping Mode, Texture Format and so on.
The class can load compressed DDS files, RAW files (with runtime compression) or create a normalisation cube map (I have 3 different functions in the class for those 3 things).
One Texture ID is generated for each Object of that class and this one can be queried via a method.

The problem now is, that I need these texture IDs in other classes, too.

I had C in school for 2 years, but we only did the basics of C++ during the last 6 months http://www.opengl.org/discussion_boards/ubb/frown.gif.

PK, you are talking about interfaces and that stuff, perhaps you could give a simple example with the help of the class I have (what you would change and that stuff).

I need no code only a "kick" into the right direction ... lets say a "C++ design lesson" http://www.opengl.org/discussion_boards/ubb/biggrin.gif.

Diapolo

Humus
11-12-2002, 11:17 AM
If you plan on using GL_ARB_fragment_program you can normalize it after filtering like this:

DP3 temp, bump, bump; # Post-filter normalisation of bumpmap
RSQ invLen, temp.x;
MUL bump, bump, invLen;

This is what I do in my Phong demo. I initially thought it would hardly affect the look, but it does wonders for closeups. http://www.opengl.org/discussion_boards/ubb/smile.gif

jwatte
11-12-2002, 06:53 PM
Wouldn't that save a register if you did this?

DP3 bump.w, bump, bump
RSQ bump.w, bump.w
MUL bump, bump, bump.w

I'm not sure the assembler could actually take that register out, as you end up with a different result in val.w at the end. And temp registers may be scarce. (Or not :-)

NitroGL
11-12-2002, 08:07 PM
Yeah, it would http://www.opengl.org/discussion_boards/ubb/smile.gif

That's pretty much the only thing I ever use .w for is normalizing (and boy do I use that a lot! http://www.opengl.org/discussion_boards/ubb/smile.gif).

Though if you store a specular exponent map in the normal map's alpha, then it would destroy that...

pkaler
11-12-2002, 09:02 PM
Originally posted by Diapolo:

I need no code only a "kick" into the right direction ... lets say a "C++ design lesson" http://www.opengl.org/discussion_boards/ubb/biggrin.gif.

Diapolo




class CTexture
{
public:

// a bunch of functions

protected:
std::string filename;
unsigned id;
};

class CCubemap : public CTexture
{
public:

// other functions you would need for a
// cubemap

protected:
// attributes of your cubemap
};

class CTextureFactory
{
public:
virtual CTexture* Load(std::string filename, WrapMode m);

protected:

};

class CCubemapFactory : public CTextureFactory
{
public:
CCubemap* Load(std::string filename, WrapMode m);

protected:
};



Alright so the CTexture and CTextureFactory classes aren't abstract interfaces, but the above should get you started.

Diapolo
11-13-2002, 03:25 AM
OK, thanks for your example.

You think I should build a base texture class, then build classes for different textures (2D, 3D, CubeMap and so on) on top of that base class?
Via class CCubemap : public CTexture, I can use the attributes and methods of the CTexture class in the CCubemap class (we didnt do that stuff in school)?

But I wonder how I could access the texture IDs in other classes, that need textures as well (I can think of some bad solutions, but not a really good one *g*)?

And what about that keyword virtual, Ive never used that stuff before http://www.opengl.org/discussion_boards/ubb/wink.gif.

Seems like many beginner questions, sorry for that http://www.opengl.org/discussion_boards/ubb/biggrin.gif.

Regards,
Diapolo

[This message has been edited by Diapolo (edited 11-13-2002).]

pkaler
11-13-2002, 10:33 AM
You think I should build a base texture class, then build classes for different textures (2D, 3D, CubeMap and so on) on top of that base class?

Good design is in the eye of the beholder. But that has worked for me so far. Don't be afraid to write a bunch of code and then refactor a month or two down the road.


Via class CCubemap : public CTexture, I can use the attributes and methods of the CTexture class in the CCubemap class (we didnt do that stuff in school)?

CCubemap inherits the attributes and functions of CTexture.




class CMesh
{
public:

protected:
CTexture mDiffusemap;
};


Is that what you mean? That's kind of the naive solution. What you'll probably want to do is code up a Texture Manager class that hands out Handles to textures so that different meshes can share textures.



And what about that keyword virtual, Ive never used that stuff before http://www.opengl.org/discussion_boards/ubb/wink.gif.


The virtual keyword says, "I may be redefined by a derived class".
Technically speaking, it activates late-binding. So the program decides at runtime if you need to call CTextureFactory::Load or CCubemapFactory::Load.


[This message has been edited by PK (edited 11-13-2002).]

Diapolo
11-13-2002, 11:48 AM
Thank you very much http://www.opengl.org/discussion_boards/ubb/smile.gif.

I will look into that whole stuff and then think about a good solution, that fits my needs.

Diapolo

mcraighead
11-13-2002, 02:11 PM
Bah, that "factory" and "design patterns" stuff was just made up to make our lives more complicated... http://www.opengl.org/discussion_boards/ubb/smile.gif

- Matt

jwatte
11-13-2002, 06:01 PM
I've found implementation inheritance to be mostly unhelpful, whereas abstract superclasses (used as interfaces) help a lot in designing a usable abstraction layer.

If the operations on a texture are, say, "bind()" and "loadFromFile()", then you'd probably want to define that as an interface using pure virtuals in your ITexture class, and then have your factory instantiate a CCubeMapTexture or CMipMappedTexture or CLookupFloatTexture depending on what the user asks of it. Each of those would derive from the abstract interface, and concretely implement those functions, in addition to whatever support the factory needs to configure them and set them operating.

Diapolo
11-13-2002, 11:23 PM
Originally posted by mcraighead:
Bah, that "factory" and "design patterns" stuff was just made up to make our lives more complicated... http://www.opengl.org/discussion_boards/ubb/smile.gif

- Matt

Dont say that Matt http://www.opengl.org/discussion_boards/ubb/wink.gif.
Quite a few NV demos use so many libs and structures and all that stuff, that Im really unable to read / understand them.
If I want to learn basics, most of them are written way to complicated.

Diapolo

MichaelK
11-14-2002, 03:29 AM
And what about templates? You can pass as an argument a set of options (number of dims, internal format, target). In that way class will be very efficent. For example:

template<DWORD num_dims, DWORD target>
class texture {
public:
void set_wrap_mode (GLenum mode) {
glTexParameteri (target, GL_TEXTURE_WRAP_S, mode);
if (num_dims >= 2)
glTex.... (...GL_T...);
// and so on for GL_R and GL_Q

}
};

Compiler should optimize this class such as unneeded instructions will be omitted because branches can be evaluated at runtime.

What do you think about this concept?

mattc
11-14-2002, 07:02 AM
sorry guys, but i just can't help thinking you're over-asbtracting things here a tad - you're talking about a really self-contained object with minimal maintance load: textures. they're used by other code, really, since they do little other than wrap low-level operations. so i'd say protocol/asbtract base classes are ok, but inheritance imposes a whole new management you might not be aware of: for example, what if you want one unique object instead of per-derived-class duplicates? inheriting base classes virtually doesn't work as it should (as msdn says) on visual c++ 6 sp5...

my point is: for a low level object like texture wrapper, all you need is decent accessor methods: set/get blah. you can create one abstract class and then derive specialised versions to match the gl texture state, then create an interface class to do all the middle work for you.

on top of all this, the performance hit for late binding (invoking a virtual method that's not pure virtual, like void foo() == 0; ) can be surprisingly high under some circumstances, so you don't wan't a possible performance hit on the renderer's inner loop. search msdn, there's info on this by a guy who's worked on the compiler, sorry i can't remember the article title, it's about achieving good optimisation in vc6 and what sort of code it the ms compiler generates...

zed
11-14-2002, 09:34 AM
>>Quite a few NV demos use so many libs and structures and all that stuff, that Im really unable to read / understand them.<<

let alone compile them without first spending a hour first farting around. http://www.opengl.org/discussion_boards/ubb/smile.gif

pkaler
11-14-2002, 10:33 AM
Originally posted by mattc:
for example, what if you want one unique object instead of per-derived-class duplicates?

I'm not sure what you're trying to say here.



inheriting base classes virtually doesn't work as it should (as msdn says) on visual c++ 6 sp5...

A lot of stuff doesn't work as it should when your using vc++. It's just stuff you have to be familliar with when working with a compiler.



on top of all this, the performance hit for late binding (invoking a virtual method that's not pure virtual, like void foo() == 0; ) can be surprisingly high under some circumstances, so you don't wan't a possible performance hit on the renderer's inner loop.


Well, you usually want to cache stuff in local variables before you hit your inner loop. Sometimes this is not possible. I'm not sure how looking up a vtable pointer will be slower than getting a member variable that is an enum and then calling a function based on this variable.

Using inheritence, the correct function is looked up implicitly. While using enums, the correct function is looked up explicitly.

mcraighead
11-14-2002, 06:25 PM
Re our demos: Don't blame me! Virtually all the GL apps I write are very minimal -- plain old GLUT apps. I use C++, but not for most of its fancy features. Of course, I think only one of my apps has ever ended up on our website.

- Matt

Diapolo
11-14-2002, 11:05 PM
I dont blame you Matt, but you work for NVIDIA and perhaps you could mention, that it would be really nice to see some demos, that are simple, minimalistic and really show the point http://www.opengl.org/discussion_boards/ubb/smile.gif (and not how complicated one can code C / C++).

Diapolo

Diapolo
11-14-2002, 11:07 PM
Originally posted by MichaelK:
And what about templates? You can pass as an argument a set of options (number of dims, internal format, target). In that way class will be very efficent. For example:

template<DWORD num_dims, DWORD target>
class texture {
public:
void set_wrap_mode (GLenum mode) {
glTexParameteri (target, GL_TEXTURE_WRAP_S, mode);
if (num_dims >= 2)
glTex.... (...GL_T...);
// and so on for GL_R and GL_Q

}
};

Compiler should optimize this class such as unneeded instructions will be omitted because branches can be evaluated at runtime.

What do you think about this concept?

I dont understand how this template is used here. We had them in school for classes and functions, where you dont specifiy a variable-type like int or float (but Ive never used them).

Diapolo

pkaler
11-15-2002, 01:42 AM
Originally posted by MichaelK:
And what about templates? You can pass as an argument a set of options (number of dims, internal format, target). In that way class will be very efficent. For example:

template<DWORD num_dims, DWORD target>
class texture {
public:
void set_wrap_mode (GLenum mode) {
glTexParameteri (target, GL_TEXTURE_WRAP_S, mode);
if (num_dims >= 2)
glTex.... (...GL_T...);
// and so on for GL_R and GL_Q

}
};

Compiler should optimize this class such as unneeded instructions will be omitted because branches can be evaluated at runtime.

What do you think about this concept?

That's a pretty cool idea. In fact, OpenGL functions are kinda like template functions. You can get glSomeFuncf, glSomeFunci, etc.

I had a prof in university who used to reminisce about the good old days when he wrote a renderer in microcode. I remember one of his lectures where he showed how to write template functions in C code using the preprocessor, a bunch of macros, and selectively inserting C-style comments into your function names and parameters. This dude was a wealth of info.

Back to your comment. That is a pretty cool idea. The problem that I see is that there may be too many template parameters.

I would have to sit down with a pen and paper and design it all out before I could see it as being feasible.

Diapolo
11-15-2002, 06:34 AM
I dont understand, how to supply num_dims and target, could someone explain that little class http://www.opengl.org/discussion_boards/ubb/frown.gif?

Diapolo

pkaler
11-15-2002, 12:22 PM
Originally posted by Diapolo:
I dont understand, how to supply num_dims and target, could someone explain that little class http://www.opengl.org/discussion_boards/ubb/frown.gif?

Diapolo




typedef texture< 2, GL_TEXTURE_2D > CTexture2D;
CTexture2D myTexture;

Diapolo
11-15-2002, 02:07 PM
Ahhhh, thank you http://www.opengl.org/discussion_boards/ubb/smile.gif.

Diapolo

Diapolo
11-17-2002, 01:09 PM
OK, Im looking for the basics, that I need, to create the Mipmap levels from a Normalmap.

I could read in the texture, pixel for pixel in a RGB triple (one byte for every component).
Every component (R, G and B) can consist of values in the range 0 to 255.
Every RGB triple represents a Vector in the normalmap in the range 0.0 to 1.0 (unsigned).
Correct the above, if something is wrong http://www.opengl.org/discussion_boards/ubb/smile.gif.

But now how do I have to use that knowledge, to down-sample and renormalize the Normalmap?

Diapolo

Diapolo
11-19-2002, 02:18 AM
Any ideas / hints?

Regards,
Diapolo

davepermen
11-19-2002, 02:35 AM
Originally posted by Diapolo:
OK, Im looking for the basics, that I need, to create the Mipmap levels from a Normalmap.

I could read in the texture, pixel for pixel in a RGB triple (one byte for every component).
Every component (R, G and B) can consist of values in the range 0 to 255.
Every RGB triple represents a Vector in the normalmap in the range 0.0 to 1.0 (unsigned).
Correct the above, if something is wrong http://www.opengl.org/discussion_boards/ubb/smile.gif.

But now how do I have to use that knowledge, to down-sample and renormalize the Normalmap?

Diapolo

its in the range -1 to 1, signed..

convert to a float, divide through 128, subtract one, and you get the 3 components..
sum up 4 normals wich result in the lowerres pixel, normalize, compress again by adding 1, dividing trough 128, store the lowrespixel. do this for every lowrespixel, upload. repeat with the lowrespixels as highres, for the next lower lowres image..

Diapolo
11-19-2002, 03:09 AM
I read in a NV PDF, that the Normalmaps Normals are in the range 0 to 1.
And the ones in Heightmaps were -1 to 1.

But since its one byte, there are only 256 possible values, that was right, or?
And if its signed the range is from -128 to +128, did I get that basic stuff right http://www.opengl.org/discussion_boards/ubb/biggrin.gif?

About the Algo to create the Mipmapsm thanks and I will look into that, when Im at home!

Regards,
Diapolo

Old GLman
11-19-2002, 03:19 PM
Diapolo,

I believe you are right about that.

What you are doing right now is all the same stuff I'm trying to get implemented. Do you mind if I send you an email with some questions I have about normal maps and dot3?

Thanks,

Old GLman

Diapolo
11-20-2002, 03:28 AM
Sure, you can send me an E-Mail http://www.opengl.org/discussion_boards/ubb/smile.gif.
Ill try my best to help you ...

But Im still unsure about the range of the Normals in the Normalmaps http://www.opengl.org/discussion_boards/ubb/frown.gif.
0 to 1 or -1 to 1

Ill quote the text from the NV PDF, that Im talking about.

Or perhaps another guru could give me a short info on that http://www.opengl.org/discussion_boards/ubb/smile.gif.

Diapolo

Diapolo
11-20-2002, 12:47 PM
Here is the info from the NV PDF BumpMappingWithRegisterCombiners.pdf, I was talking about.



Here, normals in
the [-1..1] range
are compressed to
the [0..1] range

The mostly chalk blue appearance
is because the straight up normal
is [0.5 0.5 1.0]


You see a height map on the left side and a Normalmap on the right side, so Im pretty sure, that the Normals in a Normalmap are in the 0 to 1 range.

Diapolo