{"id":150,"date":"2020-08-18T14:37:34","date_gmt":"2020-08-18T14:37:34","guid":{"rendered":"http:\/\/half4.xyz\/?p=150"},"modified":"2024-02-05T18:56:28","modified_gmt":"2024-02-05T18:56:28","slug":"part-3-theory-spectral-reflection-color-spaces","status":"publish","type":"post","link":"https:\/\/half4.xyz\/index.php\/2020\/08\/18\/part-3-theory-spectral-reflection-color-spaces\/","title":{"rendered":"Part 3 (Theory): Spectral Reflection &#038; Color Spaces"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Having spectral reflectance values is all well-and-good, but this still isn\u2019t a color we can use in a look-up table.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Representing Spectral Reflection Values<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">How do we go about converting this data into something usable? Fortunately much of this work has already been done by the Commission internationale de l\u2019\u00e9clairage (\u2018CIE\u2019, pronounced \u2018see\u2019). <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Human sight is broadly defined as being receptive to 3 colors: red, green and blue. This isn\u2019t strictly true, as discussed previously, these categorizations are human constructs and don\u2019t accurately reflect what is actually happening.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The human eye has 3 cones receptive to 3 different spectrums of visible light. Here they are illustrated across the visible spectrum:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/upload.wikimedia.org\/wikipedia\/commons\/thumb\/1\/1e\/Cones_SMJ2_E.svg\/1920px-Cones_SMJ2_E.svg.png\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">We <em>could<\/em> multiply our reflectance values by these stimulus curves to get three color values. However, due to the distribution of cones in the human eye, the values to multiply by are actually dependent on the observer\u2019s field of view.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Captain Dissilusion has a great little primer on color here, and is worth a watch:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><iframe allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen=\"\" frameborder=\"0\" height=\"540\" loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/FTKP0Y9MVus?feature=oembed\" title=\"CD \/ Color\" width=\"960\"><\/iframe><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The CIE Standard Observer and XYZ Color Space<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">To solve this problem, CIE has defined a color-mapping function we can use that standardizes on the 2\u00ba FOV. It looks like this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/upload.wikimedia.org\/wikipedia\/commons\/thumb\/8\/8f\/CIE_1931_XYZ_Color_Matching_Functions.svg\/2560px-CIE_1931_XYZ_Color_Matching_Functions.svg.png\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If we multiply our reflectance values by each of these color-matching functions, we will given three values, X, Y and Z. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These are not RGB values. RGB is a color space \u2013 a way of numerically storing colours. XYZ is another type of color space. The CIE XYZ is a device-invariant way of storing color and we use it because not all colors are equal \u2013 is is possible to have two colors that are the same, but are composed of different wavelengths of light. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">CIE XYZ is also a space from which you can convert to any other color space, such as RGB, sRGB, HSV, etc.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We can generate these curves using Gaussian functions. Gaussian functions are used to create parabola-like curves. We can generate them the following way:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/wikimedia.org\/api\/rest_v1\/media\/math\/render\/svg\/8e68dfdb090860c7df2489e272b461cc71db17a9\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Our Gaussian function<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/wikimedia.org\/api\/rest_v1\/media\/math\/render\/svg\/14e2ccbea0b37e2a56a1e6d0603ed8ed893dcc87\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Our tristimulus curves<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/wikimedia.org\/api\/rest_v1\/media\/math\/render\/svg\/14e2ccbea0b37e2a56a1e6d0603ed8ed893dcc87\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">By multiplying our reflectance values by this, we can obtain CIE XYZ values.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The sRGB Color Space<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Now to convert them to usable color information for textures. We\u2019ll convert them to sRGB as this is what we\u2019ll need to textures in UE4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To do this, we multiply our XYZ values by the RGB matrix for the 2\u00ba observer, with the D65 illuminant. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img fetchpriority=\"high\" decoding=\"async\" width=\"538\" height=\"124\" src=\"https:\/\/half4.xyz\/wp-content\/uploads\/2020\/07\/image-37.png\" alt=\"\" class=\"wp-image-293\" srcset=\"https:\/\/half4.xyz\/wp-content\/uploads\/2020\/07\/image-37.png 538w, https:\/\/half4.xyz\/wp-content\/uploads\/2020\/07\/image-37-300x69.png 300w\" sizes=\"(max-width: 538px) 100vw, 538px\" \/><figcaption class=\"wp-element-caption\">Our RGB conversion matrix, <em>m<\/em><\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">r = x * m[0][0] + y * m[0][1] + z * m[0][2]<br>g = x * m[1][0] + y * m[1][1] + z * m[1][2]<br>b = x * m[2][0] + y * m[2][1] + z * m[2][2]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"> <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In order to now get this into sRGB, we simply do a gamma correction:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">if abs(c) &gt; 0.0031308<br>\u2003c = 1.055 * c<sup>1\/2.2<\/sup> -0.055<br>else<br>\u2003c = 12.92 * c<br>where c is one of our channels, r, g or b<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After all of that work, we now have sRGB colours from our reflectance values. Now, we\u2019ll implement it<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Having spectral reflectance values is all well-and-good, but this still isn\u2019t a color we can use in a look-up table. Representing Spectral Reflection Values How do we go about converting this data into something usable? Fortunately much of this work has already been done by the Commission internationale de l\u2019\u00e9clairage (\u2018CIE\u2019, pronounced \u2018see\u2019). Human sight is broadly defined as being receptive to 3 colors: red, green and blue. This isn\u2019t strictly true, as discussed previously, these categorizations are human constructs and don\u2019t accurately reflect what is actually happening. The human eye has 3 cones receptive to 3 different spectrums of visible light. Here they are illustrated across the visible spectrum: We could multiply our reflectance values by these stimulus curves to get three color values. However, due to the distribution of cones in the human eye, the values to multiply by are actually dependent on the observer\u2019s field of view. Captain Dissilusion has a great little primer on color here, and is worth a watch: The CIE Standard Observer and XYZ Color Space To solve this problem, CIE has defined a color-mapping function we can use that standardizes on the 2\u00ba FOV. It looks like this: If we multiply our reflectance values by each of these color-matching functions, we will given three values, X, Y and Z. These are not RGB values. RGB is a color space \u2013 a way of numerically storing colours. XYZ is another type of color space. The CIE XYZ is a device-invariant way of storing color and we use it because not all colors are equal \u2013 is is possible to have two colors that are the same, but are composed of different wavelengths of light. CIE XYZ is also a space from which you can convert to any other color space, such as RGB, sRGB, HSV, etc. We can generate these curves using Gaussian functions. Gaussian functions are used to create parabola-like curves. We can generate them the following way: By multiplying our reflectance values by this, we can obtain CIE XYZ values. The sRGB Color Space Now to convert them to usable color information for textures. We\u2019ll convert them to sRGB as this is what we\u2019ll need to textures in UE4. To do this, we multiply our XYZ values by the RGB matrix for the 2\u00ba observer, with the D65 illuminant. r = x * m[0][0] + y * m[0][1] + z * m[0][2]g = x * m[1][0] + y * m[1][1] + z * m[1][2]b = x * m[2][0] + y * m[2][1] + z * m[2][2] In order to now get this into sRGB, we simply do a gamma correction: if abs(c) &gt; 0.0031308\u2003c = 1.055 * c1\/2.2 -0.055else\u2003c = 12.92 * cwhere c is one of our channels, r, g or b After all of that work, we now have sRGB colours from our reflectance values. Now, we\u2019ll implement it<\/p>\n","protected":false},"author":1,"featured_media":293,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[8,7],"class_list":["post-150","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-lut","tag-skin"],"_links":{"self":[{"href":"https:\/\/half4.xyz\/index.php\/wp-json\/wp\/v2\/posts\/150","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/half4.xyz\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/half4.xyz\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/half4.xyz\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/half4.xyz\/index.php\/wp-json\/wp\/v2\/comments?post=150"}],"version-history":[{"count":11,"href":"https:\/\/half4.xyz\/index.php\/wp-json\/wp\/v2\/posts\/150\/revisions"}],"predecessor-version":[{"id":1302,"href":"https:\/\/half4.xyz\/index.php\/wp-json\/wp\/v2\/posts\/150\/revisions\/1302"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/half4.xyz\/index.php\/wp-json\/wp\/v2\/media\/293"}],"wp:attachment":[{"href":"https:\/\/half4.xyz\/index.php\/wp-json\/wp\/v2\/media?parent=150"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/half4.xyz\/index.php\/wp-json\/wp\/v2\/categories?post=150"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/half4.xyz\/index.php\/wp-json\/wp\/v2\/tags?post=150"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}