normal_encoding.sh 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /*
  2. * Copyright 2021 elven cache. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
  4. */
  5. #ifndef NORMAL_ENCODING_SH
  6. #define NORMAL_ENCODING_SH
  7. #define NE_USE_OCTAHEDRAL_REPRESENTATION 0
  8. // From "A Survey of Efficient Representations for Independent Unit Vectors"
  9. // http://jcgt.org/published/0003/02/01/paper.pdf
  10. // Convert an oct24 (2x12bit normal) to an rgb8 value for storing in texture
  11. vec3 snorm12x2_to_unorm8x3 (vec2 f) {
  12. f = clamp(f, -1.0, 1.0);//min(max(f, vec2(-1.0)), vec2(1.0));
  13. vec2 u = floor(f * 2047.0 + 2047.5);
  14. float t = floor(u.y / 256.0);
  15. // "This code assumes that rounding will occur during storage."
  16. // -- Not certain but this appears to mainly apply to the x channel.
  17. // From paper: x = u.x / 16.0 - 0.5
  18. // Instead round by +0.5 and floor.
  19. return vec3(floor(u.x / 16.0), fract(u.x / 16.0) * 256.0 + t, u.y - t * 256.0) / 255.0;
  20. }
  21. // Unpack oct24 (2x12bit normal) from an rgb8 value stored in texture (normal spec)
  22. vec2 unorm8x3_to_snorm12x2 (vec3 u) {
  23. u *= 255.0;
  24. u.y *= (1.0 / 16.0);
  25. vec2 s = vec2(u.x * 16.0 + floor(u.y), fract(u.y) * (16.0 * 256.0) + u.z);
  26. s = s * (1.0 / 2047.0) - 1.0;
  27. return min(max(s, -1.0), 1.0);
  28. }
  29. // Built in sign test could return 0, don't want that
  30. vec2 signNotZero (vec2 v) {
  31. return vec2((v.x >= 0.0) ? 1.0 : -1.0, (v.y >= 0.0) ? 1.0 : -1.0);
  32. }
  33. // Assume normalized input. Output is (-1, 1) for each component
  34. vec2 float32x3_to_oct(vec3 v) {
  35. // Project the sphere onto the octahedron, and then onto the xy plane
  36. vec2 p = v.xy * (1.0 / (abs(v.x) + abs(v.y) + abs(v.z)));
  37. // Reflect the folds of the lower hemisphere over the diagonals
  38. return (v.z <= 0.0) ? ((1.0 - abs(p.yx)) * signNotZero(p)) : p;
  39. }
  40. // Get a float3 normal from an oct representation
  41. vec3 oct_to_float32x3 (vec2 e) {
  42. vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
  43. if (v.z < 0.0) {
  44. v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy);
  45. }
  46. return normalize(v);
  47. }
  48. vec3 SignedNormalEncodeToOct (vec3 normal) {
  49. return snorm12x2_to_unorm8x3(float32x3_to_oct(normal));
  50. }
  51. vec3 SignedNormalDecodeFromOct (vec3 normal) {
  52. return oct_to_float32x3(unorm8x3_to_snorm12x2(normal));
  53. }
  54. vec3 NormalEncode (vec3 normal)
  55. {
  56. #if NE_USE_OCTAHEDRAL_REPRESENTATION
  57. return SignedNormalEncodeToOct(normal);
  58. #else
  59. return normal * 0.5 + 0.5;
  60. #endif
  61. }
  62. vec3 NormalDecode (vec3 normal)
  63. {
  64. #if NE_USE_OCTAHEDRAL_REPRESENTATION
  65. return SignedNormalDecodeFromOct(normal);
  66. #else
  67. return normal * 2.0 - 1.0;
  68. #endif
  69. }
  70. #endif // NORMAL_ENCODING_SH