Jump to content

pbrMaterial shows hard edges of Skybox? (MacbookPro)


Recommended Posts


I'm new to Babylon.js and to this forum, so perhaps I am missing something obvious. The documentation on PBR http://doc.babylonjs.com/overviews/Physically_Based_Rendering has an image of beautiful materials with different glossiness and reflectivity values. But when I run the demo Playground Demo Scene - PBR Materials in my browser (Safari or Chrome, on a Macbook Pro), the materials look much less impressive. For low glossiness and reflectivity values, the spheres don't look "rough" with a lot of light scattering. Instead I can clearly see the edges of the skybox. See attached screenshot, the spheres in the top right corner.

Why is this happening? Is it my hardware? Did something change in the source code since the picture was taken?



[Edit] complete specs:

Chrome Version 48.0.2564.116 (64-bit) and 49.0.2623.87 (64-bit)

Safari Version 9.0.3 (10601.4.4)

MacBook Pro (Retina, 13-inch, Early 2015)
Intel Iris Graphics 6100 1536 MB
2,7 GHz Intel Core i5
8 GB 1867 MHz DDR3

Screen Shot 2016-03-15 at 16.30.44.png

Link to comment
Share on other sites


I ll try to keep the answer short but as it is actually a really good question, I may go a little bit further than the yes/no answer :)

Why this issue?

As stated by OpenGLES 2.0 (WebGL 1.0), cubemap filtering should not be seamless, it should in theory only filter on a face base and not accross faces. Regarding this, the MacOS version of Chrome is following the standard. But why are they making it happen on Windows? IT is actually a declared ticket where people are proposing to disable the filtering to be closer from the standard on none WebGL 2.0 browsers: https://bugs.chromium.org/p/chromium/issues/detail?id=479753&q=label%3ACr-blink-webgl&colspec=ID%20Pri%20M%20Stars%20ReleaseBlock%20Cr%20Status%20Owner%20Summary%20OS%20Modified

So, yes, it can seem completely random depending on your OS and Browser (even just accross OSes for the same browser)... But the truth is the browsers with the issue are following the standard.

How to solve it ?

I am quite happy that the question showed up because I spent a while figuring out how to solve it :-)

Actually, this requires the same kind of processing people used to do before hardware support for seamless cubemap filtering. To summarize the process, it consists to preprocess manually the cubemap and blur accross faces to generate all the MipMap manually. But what about the pixels nearby the edges ? Yes, they won t be filtered together so another method needs to be applied in order to reduce the edge artifacts called Edge Fixup (a few of them exist and well be using the WARP one in BJS). For more information have a read at the amazing blog from Sebastien Lagarde: https://seblagarde.wordpress.com/2012/06/10/amd-cubemapgen-for-physically-based-rendering/

You will now probably wonder how this native code could be apply in BJS ?

BJS Implementation !!!

I spent a big part of my time in the last few weeks re-implementing Cubemapgen in Typescript in Babylon JS \o/ and this works pretty nicely !!! You can find the source in this file: https://github.com/BabylonJS/Babylon.js/blob/master/src/Tools/HDR/babylon.tools.pmremgenerator.ts

The drawback of this technique is that it can be slow and requires full pixels data to work so loading the example above, be patient for loading but it should be almost seamless:


Increasing the size of the seamless texture make it better but even slower to load.

Going Forward

I am in the middle of writting a complete documentation for the PBR material and the new HDRTexture of BJS so you ll have more complete information once release in a couple of weeks !

Aside, from this, I am planning to create an offline tool to generate and pack your cube texture with MipMaps to prevent the slow loading process.

I am also keen on gathering your feedback to make it better !!

Hope the explanation was understandable and not too boring,


Link to comment
Share on other sites

Beautiful! Thanks so much Sebavan!

Now one stupid question: how do I use it for my own cubemaps? Is it as simple as setting the parameters of HDRCubeTexture()?      

var hdrTexture = new BABYLON.HDRCubeTexture("textures/country.hdr", scene, 512);
var hdrSeamLessTexture = new BABYLON.HDRCubeTexture("textures/country.hdr", scene, 64, false, true, false, true);

EDIT: to answer my own question, yes it is that easy! (Using Babylon 2.4 alpha) :D

Screen Shot 2016-03-16 at 11.12.03.png

Link to comment
Share on other sites

Thanks, I'm assuming that is also the same file format that 3DSMax creates when exporting environment maps as .hdr?

Are there other HDR file formats that are widely used?


This may be interesting to know (from https://en.wikipedia.org/wiki/Radiance_(software) ):


HDR image format[edit]

Radiance defined an image format for storing HDR images, now described as RGBE image format. Since it was the first (and for a long time the only) HDR image format, this format is supported by many other[which?] software packages.[citation needed]

The file starts with the signature '#?RADIANCE' and then several lines listing the commands used to generate the image. This information allows the renderer rpict to continue a partially completed render (either manually, or using the rad front-end). There are also key=value declarations, including the line 'FORMAT=32-bit_rle_rgbe'.

After this is a blank line signifying the end of the header. A single line describes the resolution and pixel order. As produced by the Radiance tools this always takes the form of '-Y height +X width'. After this line follows the binary pixel data.

Radiance calculates light values as floating point triplets, one each for red, green and blue. But storing a full double precision float for each channel (8 bytes × 3 = 24 bytes) is a burden even for modern systems. Two stages are used to compress the image data. The first scales the three floating point values to share a common 8-bit exponent, taken from the brightest of the three. Each value is then truncated to an 8-bit mantissa (fractional part). The result is four bytes, 32 bits, for each pixel. This results in a 6:1 compression, at the expense of reduced colour fidelity.

The second stage performs run length encoding on the 32-bit pixel values. This has a limited impact on the size of most rendered images, but it is fast and simple.


Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...