Jump to content

  • Log In with Google      Sign In   
  • Create Account


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.

  • You cannot reply to this topic
7 replies to this topic

#1 ic0de   Members   -  Reputation: 804

Like
0Likes
Like

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?

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


Sponsor:

#2 Steve_Segreto   Crossbones+   -  Reputation: 1492

Like
0Likes
Like

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.

#3 Hodgman   Moderators   -  Reputation: 28587

Like
2Likes
Like

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.


#4 lipsryme   Members   -  Reputation: 1002

Like
0Likes
Like

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.


#5 AliasBinman   Members   -  Reputation: 420

Like
2Likes
Like

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)

http://advances.realtimerendering.com/s2012/Epic/The%20Technology%20Behind%20the%20Elemental%20Demo%2016x9.pptx

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.

#6 ic0de   Members   -  Reputation: 804

Like
0Likes
Like

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"

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


#7 AliasBinman   Members   -  Reputation: 420

Like
0Likes
Like

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.

#8 Hodgman   Moderators   -  Reputation: 28587

Like
2Likes
Like

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.



PARTNERS