View more

View more

View more

### Image of the Day Submit

IOTD | Top Screenshots

### The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.

# gloss mapping?

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

7 replies to this topic

### #1ic0de  Members

Posted 02 December 2012 - 10:22 PM

Hey I just implemented gloss mapping or at least I think I did. Am I right in thinking that gloss mapping is when you change the specular exponent based on a texture? Also did I implement it right? here is my code (simplified of course):

specular = pow(max(dot(halfvec, finalnormal), 0.0), (texture2D(gloss_texture, transformedTexcoord).r*99.0) + 1.0);


Mostly I was wondering about the range, I want to be pretty conformant to what other engines use as to maximize the portability of my content. right now I noticed that when multiplying it by 99 I start running into the limitations of 8-bit grayscale. Does anyone have an example of how they implemented this effect?
Currently working on new DOS game, Chuck Jones: Space Cop of the Future, Check out my Dev Blog

you know you program too much when you start ending sentences with semicolons;

### #2Steve_Segreto  Members

Posted 03 December 2012 - 12:23 AM

Not sure about your constant, but the rest looks OK. This is how a gloss map is used to the best of my knowledge too.

### #3Hodgman  Moderators

Posted 03 December 2012 - 01:41 AM

Sometimes "gloss" terminology is a bit vague - some engines use it to mean the specular power, while others use it to mean the specular mask. In any case, it's good to fetch both the power and mask values from a texture to give your artists decent control over the materials.
In my engine, I call the specular-power texture the "roughness" texture.

You seem to be using the traditional Blinn-Phong specular function, and the code looks ok. In terms of style, I'd suggest a few more line breaks:
float NdotH = saturate(dot(halfvec, finalnormal)); //prefer saturate over max where able
float specPower = texture2D(gloss_texture, transformedTexcoord).r*99.0 + 1.0;
specular = pow(NdotH, specPower);

As for the "x*99+1" part, there is no right answer for this encoding/decoding function. Any positive value is valid for the specular power -- some materials might need "5" and others might need "50000"... This makes choosing a function that encodes this range into 8-bits particularly difficult.
If the materials in your game only need the values of 1-100, then your encoding is fine.

If you want to move more precision to the lower end, you can do something like:
float specPower = texture2D....
specPower = (specPower*specPower) * range + 1;
Or to move precision to higher values, something like:
float specPower = 1.0 - texture2D....
specPower = (1.0-(specPower*specPower)) * range + 1;
Some engines use the log function for a logarithmic distribution, but basically you've just got to choose a mapping that works for you.

Other engines might not even be using Blinn-Phong, so even if you use the same mapping, you'll get different appearances of "gloss" anyway.

Edited by Hodgman, 03 December 2012 - 01:44 AM.

### #4lipsryme  Members

Posted 03 December 2012 - 09:29 AM

Sorry to intrude but I'm curious as to why you'd prefer saturate over max ?
I was having some problems using saturate for a dot product before, were it was clamping values to 1 which should not have been.
Isn't a max much safer and precise in that respect ?

Edited by lipsryme, 03 December 2012 - 09:30 AM.

### #5AliasBinman  Members

Posted 03 December 2012 - 12:14 PM

It is common in game engines now to store the spec power in log space, even with 8 bit precicion.

i.e see how UE4 does it here (slide 30)

Frostbite2 also does it this way too (albeit with maybe a slightly different range)

Also as mentioned above a saturate will be better. Its usually free whereas max is not.

### #6ic0de  Members

Posted 03 December 2012 - 12:40 PM

Also as mentioned above a saturate will be better. Its usually free whereas max is not.

I'm using glsl, as far as I know saturate doesn't exist there, glsl has clamp() but I'm not sure if that is still "free"
Currently working on new DOS game, Chuck Jones: Space Cop of the Future, Check out my Dev Blog

you know you program too much when you start ending sentences with semicolons;

### #7AliasBinman  Members

Posted 03 December 2012 - 01:08 PM

Also as mentioned above a saturate will be better. Its usually free whereas max is not.

I'm using glsl, as far as I know saturate doesn't exist there, glsl has clamp() but I'm not sure if that is still "free"

In that case do clamp(x,0,1) and the compiler should replace with a saturate.

### #8Hodgman  Moderators

Posted 03 December 2012 - 06:04 PM

Sorry to intrude but I'm curious as to why you'd prefer saturate over max ?
I was having some problems using saturate for a dot product before, were it was clamping values to 1 which should not have been.
Isn't a max much safer and precise in that respect ?

Yes if the input is possibly > 1, then saturate isn't a valid replacement. A dot product of two normal vectors can't be > 1 though, so it's possible in this case.
Saturate/clamp(x,0,1) is preferable because it's often implemented as an instruction modifier, rather than its own instruction.
E.g. Instead of "mul ...; max ...;", the GPU ASM may just be "mul_clamped ...;"

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.