HDRI spherical map to cubemap converter

Hey, @MateuszWis. Really glad it supports HDRI now!

Are you mapping the textures differently when you upload a JPG vs when you upload an HDR image? When I upload a JPG, I’m getting pinching at the poles, but when I upload an HDR the pinching is gone, even though both images are equirectangular.


1 Like

They are mapped exactly the same, the pinching probably shows up because of JPEG compression algorithm.


Ah, that’s right! It’s not the JPEG compression, but minification filtering.

In userTexture.js you’re applying tex.minFilter = NearestFilter; to HDR formats only. Once I added that filtering method to the other format, the pinching at the poles was gone. :wink:

1 Like

Thank You! I totaly missed that.
I’ve just updated the repository and the online version with Your fix. :grinning:

1 Like


Really like this, definitely a unique resource, thank you !

I am having difficulty loading the six individual HDR into three, giving me this error in console:

RGBELoader.js: Bad File Format: bad initial token

I used this HDRI map:


I have used other 6-part hdr files without a problem (from the demo, found here: threejs webgl - materials - hdr environment mapping).

I don’t have any way to tell what the issue is here, whether it is code, resource, or what…

Any pointers would be great!

Thank you :slight_smile:


1 Like

Could be a number of things. I doubt it has anything to do with the exporter, I’ve used it before and it works well. Any chance you could post an example on JSFiddle.net so people can test it and help you out?

@marquizzo It accually has to do with the exporter, RGBELoader is searching for #?RADIANCE header which i wasn’t providing.

Thank you Peter, fixed version is already up!

Working example: https://codepen.io/matheowis/pen/XOGKzz


Oh, brilliant @marquizzo! Thank you so much, off to try now :slight_smile:

@MateuszWis Awesome tool! Any plans on adding RGBM16 support? :innocent:
three.js examples (envMap: RGBM16)

EDIT: Some relevant links…


This is really handy, thank you !

Did you not mean “-Y” here ?

@mrdoob Thank you :smile: , I don’t plan to come back to this project any time soon, but I’ll keep your suggestion in mind!

@fancyrainbow Yes I meant “-Y” :grin: , thanks!


Agree this is a fantastic implementation, I hope you do keep it going.

  • for separate layout I could be wrong but the name convention I’ve seen is/was nx, ny, nz etc instead of xn, yn ,zn, for me this would save renaming all my files after adjusting the output.

I’ve switched the seperate names :grinning:
Now they save as nx, ny, nz, px, py, pz


Just like to add another vote for RGBM16 support! That would make this really useful :grin:

1 Like

@mrdoob I’ve checked the links once again and I think that it may be easier than I initially thought. I could probably render the output to a canvas and simply save the canvas as png.
I thought that 16 stands for 16 bit, but its not, right? The example RGBM16 maps are 32bit (RGBA_8888).

I’ll do some tests on the weekend :slight_smile:


Yes, this should be easy. Just use a render target and set the target’s encoding.

Hmm… Interesting… How much smaller can you get a HDR/EXR by converting to RGBM16 PNG?.. Let’s say you had a HDRHaven 2k hdr that is normally 7.5MB, roughly what size would this be as RGBM16 PNG?

Probably quite a bit smaller. The RGBM16 Pisa cubemap example on the three.js repo is about 30% smaller than the RGBE (.hdr) version. But I think the main advantage is that you can use the browser’s built-in PNG decoder which is likely to be much faster than the three.js RGBELoader.


I think i need some help with the convertion shader

I’m using functions from encodings_pars_fragment.glsl.js

void main() {

  vec4 texelColor = texture2D( tDiffuse, vUv );

  texelColor = RGBEToLinear(texelColor);

  texelColor = LinearToGamma(texelColor, 2.2);

  texelColor = LinearToRGBM(texelColor, 6.0);

  // color test
  // texelColor = RGBMToLinear(texelColor, 6.0);

  gl_FragColor = texelColor;

My fragment shader

the output of this shader is saved to .png

Result: https://codepen.io/matheowis/pen/XOGKzz

My guess is that values that i use for gammaFactor(2.2) and maxRange(6.0) are wrong.

Any suggestions?

// initial .hdr texture, texelColor is in RGBE space

// RGBE -> linear
texelColor = RGBEToLinear(texelColor);

// texelColor now in linear space 

// linear -> gamma 2.2
texelColor = LinearToGamma(texelColor, 2.2);

// texelColor is now in gamma 2.2 space

// linear -> RGBM (!!! expects texelColor to be in linear space !!! )
texelColor = LinearToRGBM(texelColor, 6.0);

So it looks like the LinearToGamma(texelColor, 2.2) transform is not needed.