Artist wants Blinn, Phong, etc but how do I code those?

Started by
8 comments, last by FreneticPonE 10 years, 4 months ago

Hello.

I am working on a graphics engine, and our 3D artist is asking for support for different lighting models (I believe they're called that?) like Blinn, Phong, Blinn-Phong, some kind of anistropic light model and Lambert. From what I can tell, these are just different ways of calculating calculating specular lighting, except for Lambert which is just diffuse lighting. However, I can't find any information about the actual shader math needed to calculate them. The shader code for specular lighting that I can find in shader examples doesn't specify what model they use. Having done some 3D modelling myself, I know what he's talking about, but I can't find anything on how to actually implement them.

Note that I'm using deferred shading, but I have a G-buffer value over for storing some kind of shading mode selecting variable. If needed I think I can get my hands on one more variable in the G-buffer. The G-buffer currently stores diffuse color, normal and specular intensity + exponent (glossiness).

And one more question: What exactly is "specular fresnel"?

Here's my current shader code for calculating specular intensity:


vec3 viewDirection = normalize(-eyeSpace.xyz);
vec3 reflectionVector = normalize(2.0 * diffuse * normal - lightDirection);
float specular = specularIntensity * pow(max(0.0, dot(viewDirection, reflectionVector)), glossiness);
Advertisement
Side-note: To get the reflection vector, you can use the 'reflect' function instead of calculating it yourself ;)

Wikipedia will be a decent starting place - they might even link you to the original academic papers.

The basic ones you ask for (IIRC) are:
Lambert = N•L
Phong = N•L * R•V^n
Blinn-Phong = N•L * N•H^n
(H = normalize(L+V))

Generally every material will use lambert for the diffuse model (though there are others), and then a different specular model.

For anisotropic, you could look up Ward, Kajiya-Kay, GGX...

Fresnel's law in physics determines how much reflection vs refraction occur when light hits a surface.
Very simply speaking, we can say reflection = specular and refraction = diffuse.
In graphics, we usually use schlicks approximation, which is:
F = f + (1-f)*(1-N•V)^5
(where f is your original spec intensity and F is basically a new spec intensity)
This is then used to weight the specular and diffuse terms - at glancing angles (where N•V is low), much more light is reflected than refracted.
N.B. physically speaking, diffuse should also be weighted using inverse fresnel, but this is often skipped.

Yes! This is what I'm looking for! Thank you so much! I'll get on implementing as soon as I get up tomorrow!

I have one question though: What's the one I'm using at the moment called? Is it even a valid one? >_>

EDIT: Ah, that's Phong, right? I don't multiply my specular value by N.L though... I thought it looked weird at extreme angles; that could explain it.

EDIT2: What's the equation for plain Blinn? EDIT3: There is no Blinn, only Blinn-Phong?

Yeah, technically N•L isn't part of any of them -- Lambert's diffuse term is actually just "1.0"!
The N•L term is part of the rendering equation that is always there, no matter which lighting/material model (aka BRDF) is being used. This means that when writing a shader, you should multiple all lighting (diffuse and specular) by N•L.

Yeah, Blinn's specular is also called Blinn-Phong. Blinn worked on a lot of comp-graphics papers though, such as bump mapping, so his name comes up a bit.

You might see 'Blinn lighting' associated with the Cook-Torrence or Torrence-Sparrow models, which may be built upon Blinn-Phong. These models simply describe a way of combining a specular distribution function (such as phong/the above/etc) with a bunch of other terms such as Fresnel and micro-self-shadowing.

Fresnel's law in physics determines how much reflection vs refraction occur when light hits a surface.
Very simply speaking, we can say reflection = specular and refraction = diffuse.
In graphics, we usually use schlicks approximation, which is:
F = f + (1-f)*(1-N•V)^5
(where f is your original spec intensity and F is basically a new spec intensity)
This is then used to weight the specular and diffuse terms - at glancing angles (where N•V is low), much more light is reflected than refracted.
N.B. physically speaking, diffuse should also be weighted using inverse fresnel, but this is often skipped.

Note for theagentd: For physically based BRDFs, you don't want to use N•V for your fresnel equation as it's just a view space fresnel and isn't physically based. Instead, use L•H (or V•H), which is dependent on the grazing angle from the viewer towards the light, which is more accurate.

It sounds like your artists just wants you to implement some of the shading models present in 3D modeling package like Maya or 3DS Max. While it's certainly possible to do this, I would strongly suggest having a deep discussion with your artists about what he or she really needs out of your shading model(s) before you just run off and implement a bunch of them. If you're not familiar with these various shading models, then I would also recommend doing some research before having the discussion. For instance, supporting Phong and Blinn-Phong in a game makes absolutely no sense. There's no artistic or technical reason to switch between the two for different materials, and your engine would probably be better off if you just supported one of them (I would go with Blinn-Phong, it's a bit more physically accurate).

It sounds like your artists just wants you to implement some of the shading models present in 3D modeling package like Maya or 3DS Max. While it's certainly possible to do this, I would strongly suggest having a deep discussion with your artists about what he or she really needs out of your shading model(s) before you just run off and implement a bunch of them. If you're not familiar with these various shading models, then I would also recommend doing some research before having the discussion. For instance, supporting Phong and Blinn-Phong in a game makes absolutely no sense. There's no artistic or technical reason to switch between the two for different materials, and your engine would probably be better off if you just supported one of them (I would go with Blinn-Phong, it's a bit more physically accurate).

I thought it would be much more common to support multiple lighting models. Don't the big engines support multiple lighting models? How would you otherwise be able to do subsurface scattering? Or are you talking about having both Phong and Blinn-Phong in particular?

It's true that my artist probably isn't the most experienced when it comes to modeling for game development. We're having some difficulties communicating since we have so different technical terms. What he calls a "shader", I call a material. What I call a "shader", he calls a magic text file with GLSL code... He did say that Phong and Blinn-Phong were good for simulating different physical materials (one was for plastic and the other was for metal, or something like that), so I just figured that those two were essential to any engine for getting good looks. He mainly seems to be using a tool called "Marmoset" to get the material looks he wants, but I'm not 100% sure it's a very good fit for game development. The problem here is that I have very little experience with working with artists myself, so I'm not sure when to say "No! Live with it!"...

To clarify, our engine has its own material editor/viewer which is not compatible at all with Marmoset. He simply uses it to check if his maps are okay. Hopefully our homegrown material editor will be able to completely replace Marmoset. Still, are there any tools I can recommend to him that are better in our case? Maybe something with the same limitations as most game engines?

I thought it would be much more common to support multiple lighting models. Don't the big engines support multiple lighting models? How would you otherwise be able to do subsurface scattering? Or are you talking about having both Phong and Blinn-Phong in particular?

Yeah there's not much point in supporting both Phong and Blinn-Phong -- the difference between them is that Phong always produces circular highlights, whereas Blinn-Phong results in stretched highlights at glancing angles. Picture a small light reflected off a wet road, it's reflection appears as a long streak, not as a perfect circle (example).

Physically speaking, Phong just made up his formula with no basis in reality just to get something that looked pretty good, whereas Blinn-Phong is actually based on a physical model of "microfacets".

Usually you try and provide a minimum of different lighting models, for efficiency's sake.

In the last game I worked on, we had one lighting model, with a few options that could be enabled / disabled, such as sub-surface scattering, a clear-coat layer (2nd specular layer) and coloured specular masks. Different materials/shaders then used different versions of this single lighting model.

However, we were using forward-rendering, which makes managing these variations a bit simpler.


Many games that use deferred shading only have one lighting model! You can fake sub-surface scattering by blurring the lighting results in screen-space (for just those objects, via a stencil mask, etc) after you've performed regular lighting on them. You can fake anisotropic lighting by using a shader on those objects that outputs a modified normal into the G-Buffer (and then having them be lit with the same lighting code as everything else).

That's not to say that you shouldn't support multiple models -- just letting you know that many games instead choose to compromise with a standard model plus a few hacks for certain materials wink.png

Another trick that some games use is to pre-compute the specular disribution into a look-up table (2D texture).
e.g. for Blinn-Phong, one axis of the texture could represent N.H, and the other axis could represent spec-power. In the shader, you'd then get the result with:
spec = tex2D( lut, float2(dot(N,H), specPower) ).r;
You can then extend this to store LUT's for different material-types in different slices of a 3D volume texture:
spec = tex3D( lut, float3(dot(N,H), specPower, materialType) ).r;

Thank you very much for your input, Hodgman and everyone else!

After a long chat with my artist, we've decided to stick with Blinn-Phong for now since it's accurate for everything except for a perfectly reflecting surface, but we'll keep the door open for implementing more if necessary, though I doubt we will.

For fresnel, I found this article from FilmicGames and decided to simply enable it for all surfaces. I concluded that dot(V, H) looked the best, so that's what I'll be using.

I'm interested in doing sub-surface scattering and anisotropic lighting. Are there any good papers, presentations or tutorials on this? There seems to be lots of presentations of the actual results (at least for SSS) but not much on how to actually do it...

Here's a good post covering several subsurface scattering examples: http://www.iryoku.com/screen-space-subsurface-scattering

For the most part a screenspace hack has become more and more prevalent as shown above, and since it looks good enough and is quite fast there's reason for it. The basic idea is to take your diffuse lighting results in screenspace and blur it, masking to keep it on the right surfaces. Usually, as is appropriate, you blur each channel separately or at least the red channel the most, as that's going to have the most travel distance in actual subsurface scattering.

Jiminez also shared some hacks for getting scattering for lighting behind ears and etc. if you want to go that far.

This topic is closed to new replies.

Advertisement