babylon.tools.cubemaptosphericalpolynomial.ts 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /// <reference path="../../../dist/preview release/babylon.d.ts"/>
  2. module BABYLON.Internals {
  3. class FileFaceOrientation
  4. {
  5. public name: string;
  6. public worldAxisForNormal: Vector3; // the world axis corresponding to the normal to the face
  7. public worldAxisForFileX: Vector3; // the world axis corresponding to texture right x-axis in file
  8. public worldAxisForFileY: Vector3; // the world axis corresponding to texture down y-axis in file
  9. public constructor(name: string, worldAxisForNormal: Vector3, worldAxisForFileX: Vector3, worldAxisForFileY: Vector3) {
  10. this.name = name;
  11. this.worldAxisForNormal = worldAxisForNormal;
  12. this.worldAxisForFileX = worldAxisForFileX;
  13. this.worldAxisForFileY = worldAxisForFileY;
  14. }
  15. };
  16. export class CubeMapToSphericalPolynomialTools {
  17. private static FileFaces: FileFaceOrientation[] = [
  18. new FileFaceOrientation("left", new Vector3(1, 0, 0), new Vector3(0, 0, -1), new Vector3(0, -1, 0)), // +X east
  19. new FileFaceOrientation("right", new Vector3(-1, 0, 0), new Vector3(0, 0, 1), new Vector3(0, -1, 0)), // -X west
  20. new FileFaceOrientation("down", new Vector3(0, 1, 0), new Vector3(1, 0, 0), new Vector3(0, 0, 1)), // +Y north
  21. new FileFaceOrientation("up", new Vector3(0, -1, 0), new Vector3(1, 0, 0), new Vector3(0, 0, -1)), // -Y south
  22. new FileFaceOrientation("front", new Vector3(0, 0, 1), new Vector3(1, 0, 0), new Vector3(0, -1, 0)), // +Z top
  23. new FileFaceOrientation("back", new Vector3(0, 0, -1), new Vector3(-1, 0, 0), new Vector3(0, -1, 0))// -Z bottom
  24. ];
  25. public static ConvertCubeMapToSphericalPolynomial(cubeInfo: CubeMapInfo): SphericalPolynomial {
  26. var sphericalHarmonics = new SphericalHarmonics();
  27. var totalSolidAngle = 0.0;
  28. // The (u,v) range is [-1,+1], so the distance between each texel is 2/Size.
  29. var du = 2.0 / cubeInfo.size;
  30. var dv = du;
  31. // The (u,v) of the first texel is half a texel from the corner (-1,-1).
  32. var minUV = du * 0.5 - 1.0;
  33. for (var faceIndex = 0; faceIndex < 6; faceIndex++)
  34. {
  35. var fileFace = this.FileFaces[faceIndex];
  36. var dataArray = cubeInfo[fileFace.name];
  37. var v = minUV;
  38. // TODO: we could perform the summation directly into a SphericalPolynomial (SP), which is more efficient than SphericalHarmonic (SH).
  39. // This is possible because during the summation we do not need the SH-specific properties, e.g. orthogonality.
  40. // Because SP is still linear, so summation is fine in that basis.
  41. for (var y = 0; y < cubeInfo.size; y++)
  42. {
  43. var u = minUV;
  44. for (var x = 0; x < cubeInfo.size; x++)
  45. {
  46. // World direction (not normalised)
  47. var worldDirection =
  48. fileFace.worldAxisForFileX.scale(u).add(
  49. fileFace.worldAxisForFileY.scale(v)).add(
  50. fileFace.worldAxisForNormal);
  51. worldDirection.normalize();
  52. var deltaSolidAngle = Math.pow(1.0 + u * u + v * v, -3.0 / 2.0);
  53. if (1) {
  54. var r = dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0];
  55. var g = dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1];
  56. var b = dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2];
  57. var color = new Color3(r, g, b);
  58. sphericalHarmonics.addLight(worldDirection, color, deltaSolidAngle);
  59. }
  60. else {
  61. if (faceIndex == 0) {
  62. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 1;
  63. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 0;
  64. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 0;
  65. }
  66. else if (faceIndex == 1) {
  67. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 0;
  68. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 1;
  69. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 0;
  70. }
  71. else if (faceIndex == 2) {
  72. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 0;
  73. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 0;
  74. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 1;
  75. }
  76. else if (faceIndex == 3) {
  77. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 1;
  78. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 1;
  79. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 0;
  80. }
  81. else if (faceIndex == 4) {
  82. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 1;
  83. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 0;
  84. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 1;
  85. }
  86. else if (faceIndex == 5) {
  87. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0] = 0;
  88. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1] = 1;
  89. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2] = 1;
  90. }
  91. var color = new Color3(dataArray[(y * cubeInfo.size * 3) + (x * 3) + 0],
  92. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 1],
  93. dataArray[(y * cubeInfo.size * 3) + (x * 3) + 2]);
  94. sphericalHarmonics.addLight(worldDirection, color, deltaSolidAngle);
  95. }
  96. totalSolidAngle += deltaSolidAngle;
  97. u += du;
  98. }
  99. v += dv;
  100. }
  101. }
  102. var correctSolidAngle = 4.0 * Math.PI; // Solid angle for entire sphere is 4*pi
  103. var correction = correctSolidAngle / totalSolidAngle;
  104. sphericalHarmonics.scale(correction);
  105. // Additionally scale by pi -- audit needed
  106. sphericalHarmonics.scale(1.0 / Math.PI);
  107. return SphericalPolynomial.getSphericalPolynomialFromHarmonics(sphericalHarmonics);
  108. }
  109. }
  110. }