1 /////////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas 4 // Digital Ltd. LLC 5 // 6 // All rights reserved. 7 // 8 // Redistribution and use in source and binary forms, with or without 9 // modification, are permitted provided that the following conditions are 10 // met: 11 // * Redistributions of source code must retain the above copyright 12 // notice, this list of conditions and the following disclaimer. 13 // * Redistributions in binary form must reproduce the above 14 // copyright notice, this list of conditions and the following disclaimer 15 // in the documentation and/or other materials provided with the 16 // distribution. 17 // * Neither the name of Industrial Light & Magic nor the names of 18 // its contributors may be used to endorse or promote products derived 19 // from this software without specific prior written permission. 20 // 21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 // 33 /////////////////////////////////////////////////////////////////////////// 34 35 36 //----------------------------------------------------------------------------- 37 // 38 // Environment maps 39 // 40 //----------------------------------------------------------------------------- 41 42 #include <ImfEnvmap.h> 43 #include "ImathFun.h" 44 #include <algorithm> 45 #include <math.h> 46 47 using namespace std; 48 using namespace Imath; 49 50 namespace Imf { 51 namespace LatLongMap { 52 53 V2f 54 latLong (const V3f &dir) 55 { 56 float r = sqrt (dir.z * dir.z + dir.x * dir.x); 57 58 float latitude = (r < abs (dir.y))? 59 acos (r / dir.length()) * sign (dir.y): 60 asin (dir.y / dir.length()); 61 62 float longitude = (dir.z == 0 && dir.x == 0)? 0: atan2 (dir.x, dir.z); 63 64 return V2f (latitude, longitude); 65 } 66 67 68 V2f 69 latLong (const Box2i &dataWindow, const V2f &pixelPosition) 70 { 71 float latitude, longitude; 72 73 if (dataWindow.max.y > dataWindow.min.y) 74 { 75 latitude = -M_PI * 76 ((pixelPosition.y - dataWindow.min.y) / 77 (dataWindow.max.y - dataWindow.min.y) - 0.5f); 78 } 79 else 80 { 81 latitude = 0; 82 } 83 84 if (dataWindow.max.x > dataWindow.min.x) 85 { 86 longitude = -2 * M_PI * 87 ((pixelPosition.x - dataWindow.min.x) / 88 (dataWindow.max.x - dataWindow.min.x) - 0.5f); 89 } 90 else 91 { 92 longitude = 0; 93 } 94 95 return V2f (latitude, longitude); 96 } 97 98 99 V2f 100 pixelPosition (const Box2i &dataWindow, const V2f &latLong) 101 { 102 float x = latLong.y / (-2 * M_PI) + 0.5f; 103 float y = latLong.x / -M_PI + 0.5f; 104 105 return V2f (x * (dataWindow.max.x - dataWindow.min.x) + dataWindow.min.x, 106 y * (dataWindow.max.y - dataWindow.min.y) + dataWindow.min.y); 107 } 108 109 110 V2f 111 pixelPosition (const Box2i &dataWindow, const V3f &direction) 112 { 113 return pixelPosition (dataWindow, latLong (direction)); 114 } 115 116 117 V3f 118 direction (const Box2i &dataWindow, const V2f &pixelPosition) 119 { 120 V2f ll = latLong (dataWindow, pixelPosition); 121 122 return V3f (sin (ll.y) * cos (ll.x), 123 sin (ll.x), 124 cos (ll.y) * cos (ll.x)); 125 } 126 127 } // namespace LatLongMap 128 129 130 namespace CubeMap { 131 132 int 133 sizeOfFace (const Box2i &dataWindow) 134 { 135 return min ((dataWindow.max.x - dataWindow.min.x + 1), 136 (dataWindow.max.y - dataWindow.min.y + 1) / 6); 137 } 138 139 140 Box2i 141 dataWindowForFace (CubeMapFace face, const Box2i &dataWindow) 142 { 143 int sof = sizeOfFace (dataWindow); 144 Box2i dwf; 145 146 dwf.min.x = 0; 147 dwf.min.y = int (face) * sof; 148 149 dwf.max.x = dwf.min.x + sof - 1; 150 dwf.max.y = dwf.min.y + sof - 1; 151 152 return dwf; 153 } 154 155 156 V2f 157 pixelPosition (CubeMapFace face, const Box2i &dataWindow, V2f positionInFace) 158 { 159 Box2i dwf = dataWindowForFace (face, dataWindow); 160 V2f pos (0, 0); 161 162 switch (face) 163 { 164 case CUBEFACE_POS_X: 165 166 pos.x = dwf.min.x + positionInFace.y; 167 pos.y = dwf.max.y - positionInFace.x; 168 break; 169 170 case CUBEFACE_NEG_X: 171 172 pos.x = dwf.max.x - positionInFace.y; 173 pos.y = dwf.max.y - positionInFace.x; 174 break; 175 176 case CUBEFACE_POS_Y: 177 178 pos.x = dwf.min.x + positionInFace.x; 179 pos.y = dwf.max.y - positionInFace.y; 180 break; 181 182 case CUBEFACE_NEG_Y: 183 184 pos.x = dwf.min.x + positionInFace.x; 185 pos.y = dwf.min.y + positionInFace.y; 186 break; 187 188 case CUBEFACE_POS_Z: 189 190 pos.x = dwf.max.x - positionInFace.x; 191 pos.y = dwf.max.y - positionInFace.y; 192 break; 193 194 case CUBEFACE_NEG_Z: 195 196 pos.x = dwf.min.x + positionInFace.x; 197 pos.y = dwf.max.y - positionInFace.y; 198 break; 199 } 200 201 return pos; 202 } 203 204 205 void 206 faceAndPixelPosition (const V3f &direction, 207 const Box2i &dataWindow, 208 CubeMapFace &face, 209 V2f &pif) 210 { 211 int sof = sizeOfFace (dataWindow); 212 float absx = abs (direction.x); 213 float absy = abs (direction.y); 214 float absz = abs (direction.z); 215 216 if (absx >= absy && absx >= absz) 217 { 218 if (absx == 0) 219 { 220 // 221 // Special case - direction is (0, 0, 0) 222 // 223 224 face = CUBEFACE_POS_X; 225 pif = V2f (0, 0); 226 return; 227 } 228 229 pif.x = (direction.y / absx + 1) / 2 * (sof - 1); 230 pif.y = (direction.z / absx + 1) / 2 * (sof - 1); 231 232 if (direction.x > 0) 233 face = CUBEFACE_POS_X; 234 else 235 face = CUBEFACE_NEG_X; 236 } 237 else if (absy >= absz) 238 { 239 pif.x = (direction.x / absy + 1) / 2 * (sof - 1); 240 pif.y = (direction.z / absy + 1) / 2 * (sof - 1); 241 242 if (direction.y > 0) 243 face = CUBEFACE_POS_Y; 244 else 245 face = CUBEFACE_NEG_Y; 246 } 247 else 248 { 249 pif.x = (direction.x / absz + 1) / 2 * (sof - 1); 250 pif.y = (direction.y / absz + 1) / 2 * (sof - 1); 251 252 if (direction.z > 0) 253 face = CUBEFACE_POS_Z; 254 else 255 face = CUBEFACE_NEG_Z; 256 } 257 } 258 259 260 V3f 261 direction (CubeMapFace face, const Box2i &dataWindow, const V2f &positionInFace) 262 { 263 int sof = sizeOfFace (dataWindow); 264 265 V2f pos; 266 267 if (sof > 1) 268 { 269 pos = V2f (positionInFace.x / (sof - 1) * 2 - 1, 270 positionInFace.y / (sof - 1) * 2 - 1); 271 } 272 else 273 { 274 pos = V2f (0, 0); 275 } 276 277 V3f dir (1, 0, 0); 278 279 switch (face) 280 { 281 case CUBEFACE_POS_X: 282 283 dir.x = 1; 284 dir.y = pos.x; 285 dir.z = pos.y; 286 break; 287 288 case CUBEFACE_NEG_X: 289 290 dir.x = -1; 291 dir.y = pos.x; 292 dir.z = pos.y; 293 break; 294 295 case CUBEFACE_POS_Y: 296 297 dir.x = pos.x; 298 dir.y = 1; 299 dir.z = pos.y; 300 break; 301 302 case CUBEFACE_NEG_Y: 303 304 dir.x = pos.x; 305 dir.y = -1; 306 dir.z = pos.y; 307 break; 308 309 case CUBEFACE_POS_Z: 310 311 dir.x = pos.x; 312 dir.y = pos.y; 313 dir.z = 1; 314 break; 315 316 case CUBEFACE_NEG_Z: 317 318 dir.x = pos.x; 319 dir.y = pos.y; 320 dir.z = -1; 321 break; 322 } 323 324 return dir; 325 } 326 327 } // namespace CubeMap 328 } // namespace Imf 329