Field3D
|
00001 //----------------------------------------------------------------------------// 00002 00003 /* 00004 * Copyright (c) 2009 Sony Pictures Imageworks Inc 00005 * 00006 * All rights reserved. 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions 00010 * are met: 00011 * 00012 * Redistributions of source code must retain the above copyright 00013 * notice, this list of conditions and the following disclaimer. 00014 * Redistributions in binary form must reproduce the above copyright 00015 * notice, this list of conditions and the following disclaimer in the 00016 * documentation and/or other materials provided with the 00017 * distribution. Neither the name of Sony Pictures Imageworks nor the 00018 * names of its contributors may be used to endorse or promote 00019 * products derived from this software without specific prior written 00020 * permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00023 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00024 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00025 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00026 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00027 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00028 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 00029 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 00031 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00032 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 00033 * OF THE POSSIBILITY OF SUCH DAMAGE. 00034 */ 00035 00036 //----------------------------------------------------------------------------// 00037 00043 //----------------------------------------------------------------------------// 00044 00045 #include <iostream> 00046 #include <vector> 00047 00048 #include "Field.h" 00049 #include "FieldMapping.h" 00050 #include "Types.h" 00051 00052 //----------------------------------------------------------------------------// 00053 00054 using namespace boost; 00055 using namespace std; 00056 00057 //----------------------------------------------------------------------------// 00058 00059 FIELD3D_NAMESPACE_OPEN 00060 00061 //----------------------------------------------------------------------------// 00062 // Field3D namespaces 00063 //----------------------------------------------------------------------------// 00064 00065 00066 //----------------------------------------------------------------------------// 00067 // Local namespace 00068 //----------------------------------------------------------------------------// 00069 00070 namespace { 00071 00072 // Strings --- 00073 00074 const string k_mappingName("FieldMapping"); 00075 const string k_nullMappingName("NullFieldMapping"); 00076 const string k_matrixMappingName("MatrixFieldMapping"); 00077 const string k_frustumMappingName("FrustumFieldMapping"); 00078 00079 // Functions --- 00080 00081 template <class Matrix_T> 00082 bool checkMatricesIdentical(const Matrix_T &m1, const Matrix_T &m2, 00083 double tolerance) 00084 { 00085 if (m1.equalWithRelError(m2, tolerance)) { 00086 return true; 00087 } 00088 V3d s1, r1, t1, sh1, s2, r2, t2, sh2; 00089 if (!FIELD3D_EXTRACT_SHRT(m1, s1, sh1, r1, t1, false)) { 00090 return false; 00091 } 00092 if (!FIELD3D_EXTRACT_SHRT(m2, s2, sh2, r2, t2, false)) { 00093 return false; 00094 } 00095 if (!s1.equalWithRelError(s2, tolerance) || 00096 !r1.equalWithAbsError(r2, tolerance) || 00097 !t1.equalWithRelError(t2, tolerance)) { 00098 return false; 00099 } 00100 return true; 00101 } 00102 00103 } 00104 00105 //----------------------------------------------------------------------------// 00106 // FieldMapping 00107 //----------------------------------------------------------------------------// 00108 00109 FieldMapping::FieldMapping() 00110 : RefBase(), 00111 m_origin(V3i(0)), 00112 m_res(V3i(1)) 00113 { 00114 /* Empty */ 00115 } 00116 00117 //----------------------------------------------------------------------------// 00118 00119 FieldMapping::FieldMapping(const Box3i &extents) 00120 : RefBase() 00121 { 00122 setExtents(extents); 00123 } 00124 00125 //----------------------------------------------------------------------------// 00126 00127 FieldMapping::~FieldMapping() 00128 { 00129 /* Empty */ 00130 } 00131 00132 //----------------------------------------------------------------------------// 00133 00134 00135 std::string FieldMapping::className() const 00136 { 00137 return std::string(classType()); 00138 } 00139 00140 //----------------------------------------------------------------------------// 00141 00142 void FieldMapping::setExtents(const Box3i &extents) 00143 { 00144 m_origin = extents.min; 00145 m_res = extents.max - extents.min + V3i(1); 00146 extentsChanged(); 00147 } 00148 00149 //----------------------------------------------------------------------------// 00150 00151 void FieldMapping::localToVoxel(const V3d &lsP, V3d &vsP) const 00152 { 00153 vsP = m_origin + lsP * m_res; 00154 } 00155 00156 //----------------------------------------------------------------------------// 00157 00158 void FieldMapping::voxelToLocal(const V3d &vsP, V3d &lsP) const 00159 { 00160 lsP.x = FIELD3D_LERPFACTOR(vsP.x, m_origin.x, m_origin.x + m_res.x); 00161 lsP.y = FIELD3D_LERPFACTOR(vsP.y, m_origin.y, m_origin.y + m_res.y); 00162 lsP.z = FIELD3D_LERPFACTOR(vsP.z, m_origin.z, m_origin.z + m_res.z); 00163 } 00164 00165 //----------------------------------------------------------------------------// 00166 // NullFieldMapping 00167 //----------------------------------------------------------------------------// 00168 00169 std::string NullFieldMapping::className() const 00170 { 00171 return std::string(classType()); 00172 } 00173 00174 //----------------------------------------------------------------------------// 00175 00176 bool NullFieldMapping::isIdentical(FieldMapping::Ptr other, 00177 double tolerance) const 00178 { 00179 // For null mappings it's simple - if the other one is also a null mapping 00180 // then true, otherwise it's false. 00181 00182 return other->className() == k_nullMappingName; 00183 } 00184 00185 //----------------------------------------------------------------------------// 00186 00187 FieldMapping::Ptr NullFieldMapping::clone() const 00188 { 00189 return Ptr(new NullFieldMapping(*this)); 00190 } 00191 00192 //----------------------------------------------------------------------------// 00193 // MatrixFieldMapping 00194 //----------------------------------------------------------------------------// 00195 00196 MatrixFieldMapping::MatrixFieldMapping() 00197 : FieldMapping() 00198 { 00199 makeIdentity(); 00200 } 00201 00202 //----------------------------------------------------------------------------// 00203 00204 MatrixFieldMapping::MatrixFieldMapping(const Box3i &extents) 00205 : FieldMapping(extents) 00206 { 00207 makeIdentity(); 00208 } 00209 00210 //----------------------------------------------------------------------------// 00211 00212 void MatrixFieldMapping::setLocalToWorld(const M44d &lsToWs) 00213 { 00214 if (m_lsToWsCurve.numSamples() > 0) { 00215 makeIdentity(); 00216 } 00217 setLocalToWorld(0.0f, lsToWs); 00218 } 00219 00220 //----------------------------------------------------------------------------// 00221 00222 void MatrixFieldMapping::setLocalToWorld(float t, const M44d &lsToWs) 00223 { 00224 m_lsToWsCurve.addSample(t, lsToWs); 00225 updateTransform(); 00226 } 00227 00228 //----------------------------------------------------------------------------// 00229 00230 void MatrixFieldMapping::makeIdentity() 00231 { 00232 m_lsToWsCurve.clear(); 00233 updateTransform(); 00234 } 00235 00236 //----------------------------------------------------------------------------// 00237 00238 void MatrixFieldMapping::extentsChanged() 00239 { 00240 updateTransform(); 00241 } 00242 00243 //----------------------------------------------------------------------------// 00244 00245 std::string MatrixFieldMapping::className() const 00246 { 00247 return std::string(classType()); 00248 } 00249 00250 //----------------------------------------------------------------------------// 00251 00252 bool MatrixFieldMapping::isIdentical(FieldMapping::Ptr other, 00253 double tolerance) const 00254 { 00255 typedef MatrixFieldMapping::MatrixCurve::SampleVec SampleVec; 00256 00257 if (other->className() != k_matrixMappingName) { 00258 return false; 00259 } else { 00260 00261 MatrixFieldMapping::Ptr mm = 00262 FIELD_DYNAMIC_CAST<MatrixFieldMapping>(other); 00263 00264 if (mm) { 00265 00266 const SampleVec lsToWs1 = m_lsToWsCurve.samples(); 00267 const SampleVec lsToWs2 = mm->m_lsToWsCurve.samples(); 00268 const SampleVec vsToWs1 = m_vsToWsCurve.samples(); 00269 const SampleVec vsToWs2 = mm->m_vsToWsCurve.samples(); 00270 00271 size_t numSamples = lsToWs1.size(); 00272 00273 // First check if time sample counts differ 00274 // lsToWs and vsToWs are guaranteed to have same sample count. 00275 if (lsToWs1.size() != lsToWs2.size()) { 00276 return false; 00277 } 00278 00279 // Then check if all time samples match, then check localToWorld 00280 // and voxelToWorld matrices 00281 for (size_t i = 0; i < numSamples; ++i) { 00282 if (lsToWs1[i].first != lsToWs2[i].first) { 00283 return false; 00284 } 00285 if (!checkMatricesIdentical(lsToWs1[i].second, lsToWs2[i].second, 00286 tolerance)) { 00287 return false; 00288 } 00289 if (!checkMatricesIdentical(vsToWs1[i].second, vsToWs2[i].second, 00290 tolerance)) { 00291 return false; 00292 } 00293 } 00294 00295 return true; 00296 00297 } else { 00298 return false; 00299 } 00300 } 00301 return false; 00302 } 00303 00304 //----------------------------------------------------------------------------// 00305 00306 void MatrixFieldMapping::updateTransform() 00307 { 00308 typedef MatrixCurve::SampleVec::const_iterator SampleIter; 00309 00310 // Build the voxel to world space transforms --- 00311 M44d lsToVs; 00312 getLocalToVoxelMatrix(lsToVs); 00313 M44d vsToLs = lsToVs.inverse(); 00314 // Loop over all samples in lsToWs, append vsToLs and create new curve 00315 // Also handle the special case where lsToWs has no samples. In that 00316 // case m_vsToWsCurve still has to have one sample. 00317 const MatrixCurve::SampleVec &lsToWs = m_lsToWsCurve.samples(); 00318 m_vsToWsCurve.clear(); 00319 for (SampleIter i = lsToWs.begin(), end = lsToWs.end(); i != end; i++) { 00320 m_vsToWsCurve.addSample(i->first, vsToLs * i->second); 00321 } 00322 00323 // See if the curve has more than just a single sample 00324 m_isTimeVarying = m_lsToWsCurve.numSamples() > 1; 00325 00326 // Sample the time-varying transforms at time=0.0 00327 m_lsToWs = m_lsToWsCurve.linear(0.0); 00328 m_wsToLs = m_lsToWs.inverse(); 00329 m_vsToWs = vsToLs * m_lsToWs; 00330 m_wsToVs = m_vsToWs.inverse(); 00331 00332 // Precompute the voxel size 00333 V3d voxelOrigin, nextVoxel; 00334 m_vsToWs.multVecMatrix(V3d(0, 0, 0), voxelOrigin); 00335 m_vsToWs.multVecMatrix(V3d(1, 0, 0), nextVoxel); 00336 m_wsVoxelSize.x = (nextVoxel - voxelOrigin).length(); 00337 m_vsToWs.multVecMatrix(V3d(0, 1, 0), nextVoxel); 00338 m_wsVoxelSize.y = (nextVoxel - voxelOrigin).length(); 00339 m_vsToWs.multVecMatrix(V3d(0, 0, 1), nextVoxel); 00340 m_wsVoxelSize.z = (nextVoxel - voxelOrigin).length(); 00341 } 00342 00343 //----------------------------------------------------------------------------// 00344 00345 void MatrixFieldMapping::getLocalToVoxelMatrix(M44d &result) 00346 { 00347 // Local to voxel is a scale by the resolution of the field, offset 00348 // to the origin of the extents 00349 M44d scaling, translation; 00350 scaling.setScale(m_res); 00351 translation.setTranslation(m_origin); 00352 result = scaling * translation; 00353 } 00354 00355 //----------------------------------------------------------------------------// 00356 00357 FieldMapping::Ptr MatrixFieldMapping::clone() const 00358 { 00359 return Ptr(new MatrixFieldMapping(*this)); 00360 } 00361 00362 //----------------------------------------------------------------------------// 00363 // FrustumFieldMapping 00364 //----------------------------------------------------------------------------// 00365 00366 FrustumFieldMapping::FrustumFieldMapping() 00367 : FieldMapping(), 00368 m_zDistribution(PerspectiveDistribution), 00369 m_defaultState(true) 00370 { 00371 reset(); 00372 } 00373 00374 //----------------------------------------------------------------------------// 00375 00376 FrustumFieldMapping::FrustumFieldMapping(const Box3i &extents) 00377 : FieldMapping(extents) 00378 { 00379 reset(); 00380 } 00381 00382 //----------------------------------------------------------------------------// 00383 00384 void FrustumFieldMapping::setTransforms(const M44d &ssToWs, const M44d &csToWs) 00385 { 00386 setTransforms(0.0, ssToWs, csToWs); 00387 } 00388 00389 //----------------------------------------------------------------------------// 00390 00391 void FrustumFieldMapping::setTransforms(float t, 00392 const M44d &ssToWs, const M44d &csToWs) 00393 { 00394 if (m_defaultState) { 00395 clearCurves(); 00396 m_defaultState = false; 00397 } 00398 00399 // Construct local-to-world transform from ssToWs 00400 M44d lsToSs, scale, translation; 00401 scale.setScale(V3d(2.0, 2.0, 1.0)); 00402 translation.setTranslation(V3d(-1.0, -1.0, 0.0)); 00403 lsToSs = scale * translation; 00404 M44d lpsToWs = lsToSs * ssToWs; 00405 00406 // Add samples to Curves 00407 m_ssToWsCurve.addSample(t, ssToWs); 00408 m_lpsToWsCurve.addSample(t, lpsToWs); 00409 m_csToWsCurve.addSample(t, csToWs); 00410 00411 // Compute near and far planes --- 00412 00413 // Because the frustum may be skewed we can't just measure distance from 00414 // the apex of the frustum to the world-space center point of the frustum. 00415 // Instead, we transform into camera space and measure z depth there. 00416 00417 V3d lsNearP(0.5, 0.5, 0.0), lsFarP(0.5, 0.5, 1.0); 00418 V3d wsNearP, wsFarP, csNearP, csFarP; 00419 00420 lpsToWs.multVecMatrix(lsNearP, wsNearP); 00421 lpsToWs.multVecMatrix(lsFarP, wsFarP); 00422 00423 M44d wsToCs = csToWs.inverse(); 00424 wsToCs.multVecMatrix(wsNearP, csNearP); 00425 wsToCs.multVecMatrix(wsFarP, csFarP); 00426 00427 double near = -csNearP.z; 00428 double far = -csFarP.z; 00429 00430 // Catch NaN here 00431 if (isnan(near) || isnan(far)) { 00432 throw BadPerspectiveMatrix("FrustumFieldMapping::setTransforms " 00433 "received bad screen-to-world matrix"); 00434 } 00435 00436 m_nearCurve.addSample(t, near); 00437 m_farCurve.addSample(t, far); 00438 00439 computeVoxelSize(); 00440 } 00441 00442 //----------------------------------------------------------------------------// 00443 00444 void FrustumFieldMapping::reset() 00445 { 00446 // Default camera to world --- 00447 00448 M44d csToWs; 00449 csToWs.makeIdentity(); 00450 00451 // Default screen to world --- 00452 00453 double near = 1; 00454 double far = 2; 00455 double fovRadians = 45.0 * M_PI / 180.0; 00456 double invTan = 1.0 / std::tan(fovRadians / 2.0); 00457 double imageAspectRatio = 1.0; 00458 00459 M44d perspective(1, 0, 0, 0, 00460 0, 1, 0, 0, 00461 0, 0, (far) / (far - near), 1, 00462 0, 0, (- far * near) / (far - near), 0); 00463 00464 M44d fov; 00465 fov.setScale(V3d(invTan / imageAspectRatio, invTan, 1.0)); 00466 00467 M44d flipZ; 00468 flipZ.setScale(V3d(1.0, 1.0, -1.0)); 00469 00470 M44d csToSs = flipZ * perspective * fov; 00471 00472 M44d standardSsToWs = csToSs.inverse() * csToWs; 00473 00474 // Set default state --- 00475 00476 clearCurves(); 00477 setTransforms(standardSsToWs, csToWs); 00478 00479 m_defaultState = true; 00480 00481 computeVoxelSize(); 00482 } 00483 00484 //----------------------------------------------------------------------------// 00485 00486 void FrustumFieldMapping::extentsChanged() 00487 { 00488 computeVoxelSize(); 00489 } 00490 00491 //----------------------------------------------------------------------------// 00492 00493 void FrustumFieldMapping::worldToVoxel(const V3d &wsP, V3d &vsP) const 00494 { 00495 worldToVoxel(wsP, vsP, 0.0); 00496 } 00497 00498 //----------------------------------------------------------------------------// 00499 00500 void FrustumFieldMapping::worldToVoxel(const V3d &wsP, V3d &vsP, float time) const 00501 { 00502 V3d lsP; 00503 worldToLocal(wsP, lsP, time); 00504 localToVoxel(lsP, vsP); 00505 } 00506 00507 //----------------------------------------------------------------------------// 00508 00509 void FrustumFieldMapping::voxelToWorld(const V3d &vsP, V3d &wsP) const 00510 { 00511 voxelToWorld(vsP, wsP, 0.0); 00512 } 00513 00514 //----------------------------------------------------------------------------// 00515 00516 void FrustumFieldMapping::voxelToWorld(const V3d &vsP, V3d &wsP, float time) const 00517 { 00518 V3d lsP; 00519 voxelToLocal(vsP, lsP); 00520 localToWorld(lsP, wsP, time); 00521 } 00522 00523 //----------------------------------------------------------------------------// 00524 00525 void FrustumFieldMapping::worldToLocal(const V3d &wsP, V3d &lsP) const 00526 { 00527 worldToLocal(wsP, lsP, 0.0); 00528 } 00529 00530 //----------------------------------------------------------------------------// 00531 00532 void FrustumFieldMapping::worldToLocal(const V3d &wsP, V3d &lsP, float time) const 00533 { 00534 switch (m_zDistribution) { 00535 case UniformDistribution: 00536 { 00537 // First transform to local perspective space 00538 V3d lpsP; 00539 m_lpsToWsCurve.linear(time).inverse().multVecMatrix(wsP, lpsP); 00540 // Also transform to camera space 00541 V3d csP; 00542 m_csToWsCurve.linear(time).inverse().multVecMatrix(wsP, csP); 00543 // Interpolate near and far plane at current time 00544 double near = m_nearCurve.linear(time); 00545 double far = m_farCurve.linear(time); 00546 // Use perspective-space X/Y and normalized depth for Z. 00547 lsP = V3d(lpsP.x, lpsP.y, FIELD3D_LERPFACTOR(-csP.z, near, far)); 00548 break; 00549 } 00550 case PerspectiveDistribution: 00551 default: 00552 { 00553 m_lpsToWsCurve.linear(time).inverse().multVecMatrix(wsP, lsP); 00554 break; 00555 } 00556 } 00557 } 00558 00559 //----------------------------------------------------------------------------// 00560 00561 void FrustumFieldMapping::localToWorld(const V3d &lsP, V3d &wsP) const 00562 { 00563 localToWorld(lsP, wsP, 0.0); 00564 } 00565 00566 //----------------------------------------------------------------------------// 00567 00568 void FrustumFieldMapping::localToWorld(const V3d &lsP, V3d &wsP, float time) const 00569 { 00570 switch (m_zDistribution) { 00571 case UniformDistribution: 00572 { 00573 // Interpolate near and far plane at current time 00574 double near = m_nearCurve.linear(time); 00575 double far = m_farCurve.linear(time); 00576 // In this case, local space is -not- equal to local perspective space 00577 // Determine distance from camera 00578 double wsDepthFromCam = FIELD3D_LERP(near, far, lsP.z); 00579 // Transform point right in front of camera, X units away into world space 00580 V3d lpsCenterP, wsCenterP, csCenterP(0.0, 0.0, -wsDepthFromCam); 00581 m_csToWsCurve.linear(time).multVecMatrix(csCenterP, wsCenterP); 00582 // Transform center point into screen space so we know what depth 00583 // (in screen space) the voxel would live at -if- it were in local 00584 // perspective space. 00585 m_lpsToWsCurve.linear(time).inverse().multVecMatrix(wsCenterP, lpsCenterP); 00586 // Now we create a local perspective coordinate that can be transformed 00587 // using m_lpsToWsCurve 00588 V3d lpsP(lsP.x, lsP.y, lpsCenterP.z); 00589 // Now we can use m_lpsToWsCurve to transform the actual voxel location 00590 m_lpsToWsCurve.linear(time).multVecMatrix(lpsP, wsP); 00591 break; 00592 } 00593 case PerspectiveDistribution: 00594 default: 00595 { 00596 // In this case, local space and local perspective space are the same. 00597 m_lpsToWsCurve.linear(time).multVecMatrix(lsP, wsP); 00598 break; 00599 } 00600 } 00601 } 00602 00603 //----------------------------------------------------------------------------// 00604 00605 std::string FrustumFieldMapping::className() const 00606 { 00607 return std::string(classType()); 00608 } 00609 00610 //----------------------------------------------------------------------------// 00611 00612 bool FrustumFieldMapping::isIdentical(FieldMapping::Ptr other, 00613 double tolerance) const 00614 { 00615 typedef MatrixFieldMapping::MatrixCurve::SampleVec SampleVec; 00616 00617 if (other->className() != k_frustumMappingName) { 00618 return false; 00619 } else { 00620 00621 FrustumFieldMapping::Ptr fm = 00622 FIELD_DYNAMIC_CAST<FrustumFieldMapping>(other); 00623 00624 if (fm) { 00625 00626 const SampleVec lpsToWs1 = m_lpsToWsCurve.samples(); 00627 const SampleVec lpsToWs2 = fm->m_lpsToWsCurve.samples(); 00628 const SampleVec csToWs1 = m_csToWsCurve.samples(); 00629 const SampleVec csToWs2 = fm->m_csToWsCurve.samples(); 00630 00631 size_t numSamples = lpsToWs1.size(); 00632 00633 // Check that slice distributions match 00634 if (m_zDistribution != fm->m_zDistribution) { 00635 return false; 00636 } 00637 00638 // First check if time sample counts differ 00639 // lpsToWs and csToWs are guaranteed to have same sample count. 00640 if (lpsToWs1.size() != lpsToWs2.size()) { 00641 return false; 00642 } 00643 00644 // Then check if all time samples match, then check localToWorld 00645 // and voxelToWorld matrices 00646 for (size_t i = 0; i < numSamples; ++i) { 00647 if (lpsToWs1[i].first != lpsToWs2[i].first) { 00648 return false; 00649 } 00650 if (!checkMatricesIdentical(lpsToWs1[i].second, lpsToWs2[i].second, 00651 tolerance)) { 00652 return false; 00653 } 00654 if (!checkMatricesIdentical(csToWs1[i].second, csToWs2[i].second, 00655 tolerance)) { 00656 return false; 00657 } 00658 } 00659 00660 return true; 00661 00662 } else { 00663 return false; 00664 } 00665 } 00666 return false; 00667 } 00668 00669 //----------------------------------------------------------------------------// 00670 00671 V3d FrustumFieldMapping::wsVoxelSize(int /*i*/, int /*j*/, int k) const 00672 { 00673 k = std::min(std::max(k, static_cast<int>(m_origin.z)), 00674 static_cast<int>(m_origin.z + m_res.z - 1)); 00675 return m_wsVoxelSize[k - static_cast<int>(m_origin.z)]; 00676 } 00677 00678 //----------------------------------------------------------------------------// 00679 00680 void FrustumFieldMapping::computeVoxelSize() 00681 { 00682 // Precompute the voxel size --- 00683 00684 m_wsVoxelSize.resize(static_cast<int>(m_res.z),V3d(0.0)); 00685 00686 int i = m_origin.x + m_res.x / 2; 00687 int j = m_origin.y + m_res.y / 2; 00688 00689 // Do all z slices except last 00690 int zMin = static_cast<int>(m_origin.z); 00691 int zMax = static_cast<int>(m_origin.z + m_res.z - 1); 00692 00693 for (int k = zMin, idx = 0; k < zMax; ++k, ++idx) { 00694 V3d wsP, wsPx, wsPy, wsPz; 00695 V3d vsP = discToCont(V3i(i, j, k)); 00696 V3d vsPx = discToCont(V3i(i + 1, j, k)); 00697 V3d vsPy = discToCont(V3i(i, j + 1, k)); 00698 V3d vsPz = discToCont(V3i(i, j, k + 1)); 00699 voxelToWorld(vsP, wsP); 00700 voxelToWorld(vsPx, wsPx); 00701 voxelToWorld(vsPy, wsPy); 00702 voxelToWorld(vsPz, wsPz); 00703 m_wsVoxelSize[idx] = V3d((wsPx - wsP).length(), 00704 (wsPy - wsP).length(), 00705 (wsPz - wsP).length()); 00706 } 00707 00708 // Duplicate last value since there are no further slices to differentiate 00709 // against 00710 if (m_res.z >= 2) { 00711 m_wsVoxelSize[m_res.z - 1] = m_wsVoxelSize[m_res.z - 2]; 00712 } 00713 00714 } 00715 00716 //----------------------------------------------------------------------------// 00717 00718 void FrustumFieldMapping::getLocalToVoxelMatrix(M44d &result) 00719 { 00720 // Local to voxel is a scale by the resolution of the field, offset 00721 // to the origin of the extents 00722 M44d scaling, translation; 00723 scaling.setScale(m_res); 00724 translation.setTranslation(m_origin); 00725 result = scaling * translation; 00726 } 00727 00728 //----------------------------------------------------------------------------// 00729 00730 void FrustumFieldMapping::clearCurves() 00731 { 00732 m_lpsToWsCurve.clear(); 00733 m_csToWsCurve.clear(); 00734 m_nearCurve.clear(); 00735 m_farCurve.clear(); 00736 } 00737 00738 //----------------------------------------------------------------------------// 00739 00740 FieldMapping::Ptr FrustumFieldMapping::clone() const 00741 { 00742 return Ptr(new FrustumFieldMapping(*this)); 00743 } 00744 00745 //----------------------------------------------------------------------------// 00746 00747 FIELD3D_NAMESPACE_SOURCE_CLOSE 00748 00749 //----------------------------------------------------------------------------//