{"id":693,"date":"2013-05-26T15:11:55","date_gmt":"2013-05-26T15:11:55","guid":{"rendered":"http:\/\/lousodrome.net\/blog\/light\/?p=693"},"modified":"2013-05-27T06:42:24","modified_gmt":"2013-05-27T06:42:24","slug":"gamma-correct-and-hdr-rendering-in-a-32-bits-buffer","status":"publish","type":"post","link":"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/","title":{"rendered":"Gamma correct and HDR rendering in a 32 bits buffer"},"content":{"rendered":"<p>Recently I am looking for the available options for doing gamma correct and\/or HDR rendering in a 32 bits buffer. Gamma correct means you need higher precision for low values (<a href=\"http:\/\/hacksoflife.blogspot.jp\/2010\/11\/value-of-gamma-compression.html\">this article by Benjamin Supnik demonstrates why<\/a>). HDR means you may have values greater than 1, and since your range is getting wider, you want higher precision everywhere. The way to go recommended everywhere is to use 16 bits floats, like RGBA16, or even higher. But suppose you don\u2019t want your buffer to get above 32 bits, what tools are available?<\/p>\n<blockquote><p><strong>Note<\/strong>: the article has been reworked as I gathered more information. I thought organizing them was better than merely adding an update notice at the end.<\/p><\/blockquote>\n<h2>RGBM<\/h2>\n<p>My first thought was to use standard RGBA8, store the maximum of the RGB channels in the alpha channel, and store the RGB vector divided by that scale. A back of the envelope test later, I was forgetting about it, convinced it wouldn\u2019t go very far: since values are limited to the [0, 1] range, it would require to define the maximum value meant when alpha is 1. More importantly, interpolation would give incorrect results.<\/p>\n<p>Or so I thought. It seems doing this is known as RGBM (M for shared multiplier) and while indeed the interpolation gives incorrect results, <a href=\"http:\/\/graphicrants.blogspot.jp\/2009\/04\/rgbm-color-encoding.html\">this article argues they are barely noticeable<\/a>, and the other advantages outweigh it (see RGBD here after for an other worth reading article).<\/p>\n<p>There are also variations of this approach, as shown on this <a href=\"http:\/\/files.unity3d.com\/jcupisz\/rgbm\/\">online Unity demo<\/a>. <a href=\"https:\/\/gist.github.com\/aras-p\/1199797\">Here is the code<\/a>.<\/p>\n<h2>RGBD<\/h2>\n<p>By searching on the web I first found <a href=\"http:\/\/vemberaudio.se\/graphics\/RGBdiv8.pdf\">this solution, consisting in storing the inverse of the scale in the alpha channel<\/a>. Known as RGBD (D for shared divider), it doesn\u2019t suffer from having to define a maximum value, and plotting the function seems to show an acceptable precision across the range. Unfortunately it doesn\u2019t interpolate either.<\/p>\n<p><a href=\"http:\/\/iwasbeingirony.blogspot.jp\/2010\/06\/difference-between-rgbm-and-rgbd.html\">This article gives a good comparison of RGBM and RGBD<\/a>, and addresses the question of interpolation. Interestingly, it notes that while neither have correct interpolation, whether it may acceptable or not depends on the distribution of the colors.<\/p>\n<h2>RGBE<\/h2>\n<p>Then you have the RGBE (E for shared exponent): RGB and an exponent. Here is a shader <a href=\"http:\/\/www.malteclasen.de\/zib\/index4837.html?p=37\">implementation using an RGBA8 buffer<\/a>. But then again, because of the exponent being stored in the alpha channel, interpolation is going to be an issue.<\/p>\n<h2>RGB9_E5<\/h2>\n<p>Further searching, I stumbled upon the <a href=\"http:\/\/www.opengl.org\/registry\/specs\/EXT\/texture_shared_exponent.txt\">OpenGL EXT_texture_shared_exponent extension<\/a>, which defines a GL_RGB9_E5 texture format with three 9 bits components for the color channels, and an additional 5 bits exponent shared by the channels. This sounded nice: 9 bits of precision is already twice as many shades, and the exponent gives precision everywhere, as long as the channels values have the same order of magnitude. Because it is a standard format, I assume interpolation is going to be a non issue. Unfortunately as can be read on the OpenGL wiki, <a href=\"http:\/\/www.opengl.org\/wiki\/Image_Formats#Special_color_formats\">while this is a required texture format, it is not required for renderbuffers<\/a>. In other words: chances are it\u2019s not going to be implemented.<\/p>\n<h2>LogLUV<\/h2>\n<p>Since we really want a wide range of light intensity, a different approach is to use a different color space. Several people mentioned LogLUV, which I hear gives good results, at the expense of a high instruction cost for both packing and unpacking. <a href=\"http:\/\/realtimecollisiondetection.net\/blog\/?p=15\">Here is a detailed explanation<\/a>.<\/p>\n<h2>R11G11B10<\/h2>\n<p>There is still the <a href=\"http:\/\/www.opengl.org\/wiki\/Small_Float_Formats#R11F_G11F_B10F\">R11F_G11F_B10F format<\/a> (<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/bb173059%28v=vs.85%29.aspx\">DXGI_FORMAT_R11G11B10_FLOAT<\/a> in DirectX) where R and G channels have a 6 bits mantissa and a 5 bits exponent, and B has a 5 bits mantissa and 5 bits exponent. Since floats have higher precision with low values, this seem very well suited to gamma correct rendering. And since this is a standard format, interpolation should be a non issue.<\/p>\n<h2>Conclusion<\/h2>\n<p>I haven\u2019t tested in practice yet, but from these readings it seems to me the sensible solution would be to use a R11G11B10 float format when available. Otherwise (for example on mobile platforms) choose between RGBM and RGBD depending on the kind of image being rendered. Unless the format is standard, it seems interpolation is always going to be an issue, and the best you can do is mitigate by choosing the solution depending on your use case.<\/p>\n<p>Did I miss something?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently I am looking for the available options for doing gamma correct and\/or HDR rendering in a 32 bits buffer. Gamma correct means you need higher precision for low values (this article by Benjamin Supnik demonstrates why). HDR means you &hellip; <a href=\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[17],"tags":[374,396,388,194,387,395,198,394,44,385,392,393,391,390,389,386],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v20.13 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Gamma correct and HDR rendering in a 32 bits buffer &ndash; Light is beautiful<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Gamma correct and HDR rendering in a 32 bits buffer &ndash; Light is beautiful\" \/>\n<meta property=\"og:description\" content=\"Recently I am looking for the available options for doing gamma correct and\/or HDR rendering in a 32 bits buffer. Gamma correct means you need higher precision for low values (this article by Benjamin Supnik demonstrates why). HDR means you &hellip; Continue reading &rarr;\" \/>\n<meta property=\"og:url\" content=\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/\" \/>\n<meta property=\"og:site_name\" content=\"Light is beautiful\" \/>\n<meta property=\"article:published_time\" content=\"2013-05-26T15:11:55+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2013-05-27T06:42:24+00:00\" \/>\n<meta name=\"author\" content=\"Julien Guertault\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@Zavie\" \/>\n<meta name=\"twitter:site\" content=\"@Zavie\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Julien Guertault\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/#article\",\"isPartOf\":{\"@id\":\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/\"},\"author\":{\"name\":\"Julien Guertault\",\"@id\":\"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/a16a2a69d73eca763ffdf125c49eaa2f\"},\"headline\":\"Gamma correct and HDR rendering in a 32 bits buffer\",\"datePublished\":\"2013-05-26T15:11:55+00:00\",\"dateModified\":\"2013-05-27T06:42:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/\"},\"wordCount\":732,\"commentCount\":4,\"publisher\":{\"@id\":\"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/a16a2a69d73eca763ffdf125c49eaa2f\"},\"keywords\":[\"color\",\"DirectX\",\"framebuffer\",\"gamma correction\",\"HDR\",\"interpolation\",\"linear space\",\"LogLUV\",\"OpenGL\",\"rgba\",\"RGBD\",\"RGBE\",\"RGBM\",\"shader multiplier\",\"shared divider\",\"shared exponent\"],\"articleSection\":[\"Rendering\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/\",\"url\":\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/\",\"name\":\"Gamma correct and HDR rendering in a 32 bits buffer &ndash; Light is beautiful\",\"isPartOf\":{\"@id\":\"https:\/\/lousodrome.net\/blog\/light\/#website\"},\"datePublished\":\"2013-05-26T15:11:55+00:00\",\"dateModified\":\"2013-05-27T06:42:24+00:00\",\"breadcrumb\":{\"@id\":\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/lousodrome.net\/blog\/light\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Gamma correct and HDR rendering in a 32 bits buffer\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/lousodrome.net\/blog\/light\/#website\",\"url\":\"https:\/\/lousodrome.net\/blog\/light\/\",\"name\":\"Light is beautiful\",\"description\":\"Thoughts of a graphics programmer, demoscener and spare time photographer\",\"publisher\":{\"@id\":\"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/a16a2a69d73eca763ffdf125c49eaa2f\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/lousodrome.net\/blog\/light\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/a16a2a69d73eca763ffdf125c49eaa2f\",\"name\":\"Julien Guertault\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/image\/\",\"url\":\"http:\/\/2.gravatar.com\/avatar\/2e5fc7a18e1701e1bb61a5da0ef35cf7?s=96&d=identicon&r=g\",\"contentUrl\":\"http:\/\/2.gravatar.com\/avatar\/2e5fc7a18e1701e1bb61a5da0ef35cf7?s=96&d=identicon&r=g\",\"caption\":\"Julien Guertault\"},\"logo\":{\"@id\":\"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/image\/\"},\"url\":\"http:\/\/lousodrome.net\/blog\/light\/author\/admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Gamma correct and HDR rendering in a 32 bits buffer &ndash; Light is beautiful","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/","og_locale":"en_US","og_type":"article","og_title":"Gamma correct and HDR rendering in a 32 bits buffer &ndash; Light is beautiful","og_description":"Recently I am looking for the available options for doing gamma correct and\/or HDR rendering in a 32 bits buffer. Gamma correct means you need higher precision for low values (this article by Benjamin Supnik demonstrates why). HDR means you &hellip; Continue reading &rarr;","og_url":"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/","og_site_name":"Light is beautiful","article_published_time":"2013-05-26T15:11:55+00:00","article_modified_time":"2013-05-27T06:42:24+00:00","author":"Julien Guertault","twitter_card":"summary_large_image","twitter_creator":"@Zavie","twitter_site":"@Zavie","twitter_misc":{"Written by":"Julien Guertault","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/#article","isPartOf":{"@id":"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/"},"author":{"name":"Julien Guertault","@id":"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/a16a2a69d73eca763ffdf125c49eaa2f"},"headline":"Gamma correct and HDR rendering in a 32 bits buffer","datePublished":"2013-05-26T15:11:55+00:00","dateModified":"2013-05-27T06:42:24+00:00","mainEntityOfPage":{"@id":"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/"},"wordCount":732,"commentCount":4,"publisher":{"@id":"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/a16a2a69d73eca763ffdf125c49eaa2f"},"keywords":["color","DirectX","framebuffer","gamma correction","HDR","interpolation","linear space","LogLUV","OpenGL","rgba","RGBD","RGBE","RGBM","shader multiplier","shared divider","shared exponent"],"articleSection":["Rendering"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/#respond"]}]},{"@type":"WebPage","@id":"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/","url":"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/","name":"Gamma correct and HDR rendering in a 32 bits buffer &ndash; Light is beautiful","isPartOf":{"@id":"https:\/\/lousodrome.net\/blog\/light\/#website"},"datePublished":"2013-05-26T15:11:55+00:00","dateModified":"2013-05-27T06:42:24+00:00","breadcrumb":{"@id":"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/"]}]},{"@type":"BreadcrumbList","@id":"http:\/\/lousodrome.net\/blog\/light\/2013\/05\/26\/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/lousodrome.net\/blog\/light\/"},{"@type":"ListItem","position":2,"name":"Gamma correct and HDR rendering in a 32 bits buffer"}]},{"@type":"WebSite","@id":"https:\/\/lousodrome.net\/blog\/light\/#website","url":"https:\/\/lousodrome.net\/blog\/light\/","name":"Light is beautiful","description":"Thoughts of a graphics programmer, demoscener and spare time photographer","publisher":{"@id":"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/a16a2a69d73eca763ffdf125c49eaa2f"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/lousodrome.net\/blog\/light\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/a16a2a69d73eca763ffdf125c49eaa2f","name":"Julien Guertault","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/image\/","url":"http:\/\/2.gravatar.com\/avatar\/2e5fc7a18e1701e1bb61a5da0ef35cf7?s=96&d=identicon&r=g","contentUrl":"http:\/\/2.gravatar.com\/avatar\/2e5fc7a18e1701e1bb61a5da0ef35cf7?s=96&d=identicon&r=g","caption":"Julien Guertault"},"logo":{"@id":"https:\/\/lousodrome.net\/blog\/light\/#\/schema\/person\/image\/"},"url":"http:\/\/lousodrome.net\/blog\/light\/author\/admin\/"}]}},"_links":{"self":[{"href":"http:\/\/lousodrome.net\/blog\/light\/wp-json\/wp\/v2\/posts\/693"}],"collection":[{"href":"http:\/\/lousodrome.net\/blog\/light\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/lousodrome.net\/blog\/light\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/lousodrome.net\/blog\/light\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/lousodrome.net\/blog\/light\/wp-json\/wp\/v2\/comments?post=693"}],"version-history":[{"count":0,"href":"http:\/\/lousodrome.net\/blog\/light\/wp-json\/wp\/v2\/posts\/693\/revisions"}],"wp:attachment":[{"href":"http:\/\/lousodrome.net\/blog\/light\/wp-json\/wp\/v2\/media?parent=693"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/lousodrome.net\/blog\/light\/wp-json\/wp\/v2\/categories?post=693"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/lousodrome.net\/blog\/light\/wp-json\/wp\/v2\/tags?post=693"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}