Jump to content
  • Advertisement
Sign in to follow this  

PBR (blurry reflections)

This topic is 1550 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts



so I am writing a PBR shader to experiment with the latest techniques, and I find the metalness, roughness and how they relate the the blurry reflections a bit confusing. I understand that the rougher the surface, the more blurry the cubemap will be. For my tests, I have a cubemap generated using CubemapGen, which I sample like this to get the blurred texel:

half current = roughness * 6;
half f0 = floor(current);
half f1 = ceil(current);
half f = saturate(current - f0) / (f1-f0);
half3 reflectDir = reflect(V, N_WS);
half4 reflection1 = texCUBElod (_IndirectLightTex, float4(reflectDir, f0));
half4 reflection2 = texCUBElod (_IndirectLightTex, float4(reflectDir, f1));
half4 reflection = lerp(reflection1, reflection2, f);

Where does metalness come in though? As I understand from the articles that I've been reading, the more metallic a surface, the more reflection it has (and less albedo). Is it as simple as this?

half3 totalReflection = metalness * reflection;

As a clarification, my roughness comes from the alpha channel of the main texture, and the metalness comes from the vertex color.



Share this post

Link to post
Share on other sites

As I understand from the articles that I've been reading, the more metallic a surface, the more reflection it has (and less albedo). Is it as simple as this?

Basically, yes. But there's more to it. There are other properties like the reflection color, shape, surface smoothness, etc.

PBR and BRDF is a huge topic, with many different models (Phong-model is a very basic BRDF).


What article are you reading? What are you trying to achieve?

I don't see any PBR in the code you posted. The shader does environment mapping with a very crude constant specular attenuation function. Unless the physics is baked into the env-map, this is not a real physical model.

Edited by N.I.B.

Share this post

Link to post
Share on other sites

Hi NIB, thanks for your reply.


So for our mobile project, we want to do a hybrid technique as follows:

- we have our albedo and we multiply it with a lightmap authored in maya, so the ship diffuse lighting is basically static

- then we add the specular component on top of that, taking *some* PBR ideas into the equation (like energy conservation, metalness and roughness), to mimic different surface types. We have plastic, metal, brushed metal, and so on.


The reason for doing this came up after multiple approaches to he problem (artists also wanted to try the PBR tech), seems to give the best result. Although of course this not exactly PBR, my initial post was misleading.

The reflection will also use a blurry reflection model on higher end devices (based on the surface's roughness).


The main article that I've been studying is the Remember Me tech article about their PBR tech, and also Lagarde's articles on his blog regarding Fresnel and reflectance.

Share this post

Link to post
Share on other sites

You can also check http://blog.selfshadow.com/publications/s2012-shading-course/gotanda/s2012_pbs_beyond_blinn_slides_v3.pdf but if you know Lagarde maybe you already know Gotanda as well.


You might want to modulate the energy that you read from your lightmap. Empirically : no specular = maximum diffuse power. high specular = high energy concentration in the reflection therefore no more energy for the diffuse part. You need somekind of balance so that the albedo is always inferior to 1.

Also you cannot state "the more reflection the less albedo". albedo is the integral of the radiance over the hemisphere, and to be physically correct, it cannot be greater than the irradiance. So one would expect rather "the more reflection the same the albedo". This would mean exactly what I said, the diffuse part must get darker in order for the albedo to not vary. If you had the same diffuse component, then "the more reflection the more the albedo", because the specular zone would augment the interal and make the total emnitted power (the albedo), higher.

I hope that's clear, it might be easier to hear than to read.

Share this post

Link to post
Share on other sites

It makes sense in a way, yes. I am just trying to get my head around this concept, I've been reading the article you sent me.


How I do my energy conservation:

half diffuseScale = 1 - specular;
diffuse *= diffuseScale;

// calculate final color
half4 color = diffuse + specular + reflection*metalness;

The specular is calculated in a similar fashion as in Remember Me article. I will carry on on Monday, perhaps do some more tests during the weekend.

Share this post

Link to post
Share on other sites

half-precision (or even fixed) floats are generally faster than 32bit floats, especially on mobile hardware. I'm just trying to squeeze out every performance that the powervr chips have to offer :)

Share this post

Link to post
Share on other sites

Right, so I restructured my shader to something which seems to be correct.

Basically I have 2 material modes, metallic and non metallic (as UE4 does), and if I want anything in between, I interpolate. The shader code as it stands now looks like this:

half3 reflection = texCUBEbias (_ReflectionTex, float4(i.reflectDir, (1-roughness)*6));
half specPower = exp2(10 * roughness + Log2Of1OnLn2_Plus1);
half3 light = DecodeLightmap(lightmap);
half3 fresnel = schlick(NdotV, metalness);

half3 specular =  (LN2DIV8 * specPower + 0.25) * SphericalGaussianApprox(HdotN, specPower) * fresnel;
half3 ec = saturate(1 - (specular + reflection));
half3 plastic = albedo.rgb * light * ec + specular;
half3 metallic = (specular*albedo + reflection * albedo.rgb) * Luminance(light);

return half4(lerp(plastic, metallic, metalness), 1);

I am also using Lagarde's spherical gaussian approximation for the specular component which saves me quite a bit with negligible quality loss. Thumbs up for that!


So basically if it's metal, I ignore the albedo and simply have specular + reflection, multiplied by the lightmap.

If it's plastic, I use the albedo times lightmap, with added specular.


The specular colour depends on the metalness. For metals, it's coloured (using the albedo), for non-metals it's constant white.

The result looks like this (all the spheres have an albedo of "gold", but metalness and roughness varies diagonally, specular on the plastic balls is there, but it's hidden by the geometry at times)




The reflection cubemap is not prefiltered properly, so that's my next step!


Total fragment shader cost is about 27 instructions, with room for more optimisation.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!