00001
00032 #include "linden_common.h"
00033
00034 #include "llmath.h"
00035 #include "llcamera.h"
00036
00037
00038
00039 LLCamera::LLCamera() :
00040 LLCoordFrame(),
00041 mView(DEFAULT_FIELD_OF_VIEW),
00042 mAspect(DEFAULT_ASPECT_RATIO),
00043 mViewHeightInPixels( -1 ),
00044 mNearPlane(DEFAULT_NEAR_PLANE),
00045 mFarPlane(DEFAULT_FAR_PLANE),
00046 mFixedDistance(-1.f),
00047 mPlaneCount(6)
00048 {
00049 calculateFrustumPlanes();
00050 }
00051
00052
00053 LLCamera::LLCamera(F32 z_field_of_view, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane) :
00054 LLCoordFrame(),
00055 mView(z_field_of_view),
00056 mAspect(aspect_ratio),
00057 mViewHeightInPixels(view_height_in_pixels),
00058 mNearPlane(near_plane),
00059 mFarPlane(far_plane),
00060 mFixedDistance(-1.f),
00061 mPlaneCount(6)
00062 {
00063 if (mView < MIN_FIELD_OF_VIEW) { mView = MIN_FIELD_OF_VIEW; }
00064 else if (mView > MAX_FIELD_OF_VIEW) { mView = MAX_FIELD_OF_VIEW; }
00065
00066 if (mAspect < MIN_ASPECT_RATIO) { mAspect = MIN_ASPECT_RATIO; }
00067 else if (mAspect > MAX_ASPECT_RATIO) { mAspect = MAX_ASPECT_RATIO; }
00068
00069 if (mNearPlane < MIN_NEAR_PLANE) { mNearPlane = MIN_NEAR_PLANE; }
00070 else if (mNearPlane > MAX_NEAR_PLANE) { mNearPlane = MAX_NEAR_PLANE; }
00071
00072 if (mFarPlane < 0) { mFarPlane = DEFAULT_FAR_PLANE; }
00073 else if (mFarPlane < MIN_FAR_PLANE) { mFarPlane = MIN_FAR_PLANE; }
00074 else if (mFarPlane > MAX_FAR_PLANE) { mFarPlane = MAX_FAR_PLANE; }
00075
00076 calculateFrustumPlanes();
00077 }
00078
00079
00080
00081
00082
00083 void LLCamera::setUserClipPlane(LLPlane plane)
00084 {
00085 mPlaneCount = 7;
00086 mAgentPlanes[6].p = plane;
00087 mAgentPlanes[6].mask = calcPlaneMask(plane);
00088 }
00089
00090 void LLCamera::disableUserClipPlane()
00091 {
00092 mPlaneCount = 6;
00093 }
00094
00095 void LLCamera::setView(F32 field_of_view)
00096 {
00097 mView = field_of_view;
00098 if (mView < MIN_FIELD_OF_VIEW) { mView = MIN_FIELD_OF_VIEW; }
00099 else if (mView > MAX_FIELD_OF_VIEW) { mView = MAX_FIELD_OF_VIEW; }
00100 calculateFrustumPlanes();
00101 }
00102
00103 void LLCamera::setViewHeightInPixels(S32 height)
00104 {
00105 mViewHeightInPixels = height;
00106
00107
00108 calculateFrustumPlanes();
00109 }
00110
00111 void LLCamera::setAspect(F32 aspect_ratio)
00112 {
00113 mAspect = aspect_ratio;
00114 if (mAspect < MIN_ASPECT_RATIO) { mAspect = MIN_ASPECT_RATIO; }
00115 else if (mAspect > MAX_ASPECT_RATIO) { mAspect = MAX_ASPECT_RATIO; }
00116 calculateFrustumPlanes();
00117 }
00118
00119
00120 void LLCamera::setNear(F32 near_plane)
00121 {
00122 mNearPlane = near_plane;
00123 if (mNearPlane < MIN_NEAR_PLANE) { mNearPlane = MIN_NEAR_PLANE; }
00124 else if (mNearPlane > MAX_NEAR_PLANE) { mNearPlane = MAX_NEAR_PLANE; }
00125 calculateFrustumPlanes();
00126 }
00127
00128
00129 void LLCamera::setFar(F32 far_plane)
00130 {
00131 mFarPlane = far_plane;
00132 if (mFarPlane < MIN_FAR_PLANE) { mFarPlane = MIN_FAR_PLANE; }
00133 else if (mFarPlane > MAX_FAR_PLANE) { mFarPlane = MAX_FAR_PLANE; }
00134 calculateFrustumPlanes();
00135 }
00136
00137
00138
00139
00140 size_t LLCamera::writeFrustumToBuffer(char *buffer) const
00141 {
00142 memcpy(buffer, &mView, sizeof(F32));
00143 buffer += sizeof(F32);
00144 memcpy(buffer, &mAspect, sizeof(F32));
00145 buffer += sizeof(F32);
00146 memcpy(buffer, &mNearPlane, sizeof(F32));
00147 buffer += sizeof(F32);
00148 memcpy(buffer, &mFarPlane, sizeof(F32));
00149 return 4*sizeof(F32);
00150 }
00151
00152 size_t LLCamera::readFrustumFromBuffer(const char *buffer)
00153 {
00154 memcpy(&mView, buffer, sizeof(F32));
00155 buffer += sizeof(F32);
00156 memcpy(&mAspect, buffer, sizeof(F32));
00157 buffer += sizeof(F32);
00158 memcpy(&mNearPlane, buffer, sizeof(F32));
00159 buffer += sizeof(F32);
00160 memcpy(&mFarPlane, buffer, sizeof(F32));
00161 return 4*sizeof(F32);
00162 }
00163
00164
00165
00166
00167 S32 LLCamera::AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius)
00168 {
00169 static const LLVector3 scaler[] = {
00170 LLVector3(-1,-1,-1),
00171 LLVector3( 1,-1,-1),
00172 LLVector3(-1, 1,-1),
00173 LLVector3( 1, 1,-1),
00174 LLVector3(-1,-1, 1),
00175 LLVector3( 1,-1, 1),
00176 LLVector3(-1, 1, 1),
00177 LLVector3( 1, 1, 1)
00178 };
00179
00180 U8 mask = 0;
00181 S32 result = 2;
00182
00183 for (U32 i = 0; i < mPlaneCount; i++)
00184 {
00185 mask = mAgentPlanes[i].mask;
00186 LLPlane p = mAgentPlanes[i].p;
00187 LLVector3 n = LLVector3(p);
00188 float d = p.mV[3];
00189 LLVector3 rscale = radius.scaledVec(scaler[mask]);
00190
00191 LLVector3 minp = center - rscale;
00192 LLVector3 maxp = center + rscale;
00193
00194 if (n * minp > -d)
00195 {
00196 return 0;
00197 }
00198
00199 if (n * maxp > -d)
00200 {
00201 result = 1;
00202 }
00203 }
00204
00205 return result;
00206 }
00207
00208 S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& radius)
00209 {
00210 static const LLVector3 scaler[] = {
00211 LLVector3(-1,-1,-1),
00212 LLVector3( 1,-1,-1),
00213 LLVector3(-1, 1,-1),
00214 LLVector3( 1, 1,-1),
00215 LLVector3(-1,-1, 1),
00216 LLVector3( 1,-1, 1),
00217 LLVector3(-1, 1, 1),
00218 LLVector3( 1, 1, 1)
00219 };
00220
00221 U8 mask = 0;
00222 S32 result = 2;
00223
00224 for (U32 i = 0; i < mPlaneCount; i++)
00225 {
00226 if (i == 5)
00227 {
00228 continue;
00229 }
00230
00231 mask = mAgentPlanes[i].mask;
00232 LLPlane p = mAgentPlanes[i].p;
00233 LLVector3 n = LLVector3(p);
00234 float d = p.mV[3];
00235 LLVector3 rscale = radius.scaledVec(scaler[mask]);
00236
00237 LLVector3 minp = center - rscale;
00238 LLVector3 maxp = center + rscale;
00239
00240 if (n * minp > -d)
00241 {
00242 return 0;
00243 }
00244
00245 if (n * maxp > -d)
00246 {
00247 result = 1;
00248 }
00249 }
00250
00251 return result;
00252 }
00253
00254 int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius)
00255 {
00256 LLVector3 dist = sphere_center-mFrustCenter;
00257 float dsq = dist * dist;
00258 float rsq = mFarPlane*0.5f + radius;
00259 rsq *= rsq;
00260
00261 if (dsq < rsq)
00262 {
00263 return 1;
00264 }
00265
00266 return 0;
00267 }
00268
00269
00270
00271
00272
00273 int LLCamera::sphereInFrustumOld(const LLVector3 &sphere_center, const F32 radius) const
00274 {
00275
00276
00277 F32 x, y, z, rightDist, leftDist, topDist, bottomDist;
00278
00279
00280
00281
00282 LLVector3 rel_center(sphere_center);
00283 rel_center -= mOrigin;
00284
00285 bool all_in = TRUE;
00286
00287
00288 x = mXAxis * rel_center;
00289 if (x < MIN_NEAR_PLANE - radius)
00290 {
00291 return 0;
00292 }
00293 else if (x < MIN_NEAR_PLANE + radius)
00294 {
00295 all_in = FALSE;
00296 }
00297
00298 if (x > mFarPlane + radius)
00299 {
00300 return 0;
00301 }
00302 else if (x > mFarPlane - radius)
00303 {
00304 all_in = FALSE;
00305 }
00306
00307
00308 y = mYAxis * rel_center;
00309
00310
00311 rightDist = x * mLocalPlanes[PLANE_RIGHT][VX] + y * mLocalPlanes[PLANE_RIGHT][VY];
00312 if (rightDist < -radius)
00313 {
00314 return 0;
00315 }
00316 else if (rightDist < radius)
00317 {
00318 all_in = FALSE;
00319 }
00320
00321 leftDist = x * mLocalPlanes[PLANE_LEFT][VX] + y * mLocalPlanes[PLANE_LEFT][VY];
00322 if (leftDist < -radius)
00323 {
00324 return 0;
00325 }
00326 else if (leftDist < radius)
00327 {
00328 all_in = FALSE;
00329 }
00330
00331
00332 z = mZAxis * rel_center;
00333
00334 topDist = x * mLocalPlanes[PLANE_TOP][VX] + z * mLocalPlanes[PLANE_TOP][VZ];
00335 if (topDist < -radius)
00336 {
00337 return 0;
00338 }
00339 else if (topDist < radius)
00340 {
00341 all_in = FALSE;
00342 }
00343
00344 bottomDist = x * mLocalPlanes[PLANE_BOTTOM][VX] + z * mLocalPlanes[PLANE_BOTTOM][VZ];
00345 if (bottomDist < -radius)
00346 {
00347 return 0;
00348 }
00349 else if (bottomDist < radius)
00350 {
00351 all_in = FALSE;
00352 }
00353
00354 if (all_in)
00355 {
00356 return 2;
00357 }
00358
00359 return 1;
00360 }
00361
00362
00363
00364
00365
00366
00367
00368
00369 int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) const
00370 {
00371
00372 int res = 2;
00373 for (int i = 0; i < 6; i++)
00374 {
00375 float d = mAgentPlanes[i].p.dist(sphere_center);
00376
00377 if (d > radius)
00378 {
00379 return 0;
00380 }
00381
00382 if (d > -radius)
00383 {
00384 res = 1;
00385 }
00386 }
00387
00388 return res;
00389 }
00390
00391
00392
00393 F32 LLCamera::heightInPixels(const LLVector3 ¢er, F32 radius ) const
00394 {
00395 if (radius == 0.f) return 0.f;
00396
00397
00398 if (mViewHeightInPixels > -1)
00399 {
00400
00401 LLVector3 vec = center - mOrigin;
00402
00403
00404 F32 dist = vec.magVec();
00405
00406
00407 F32 angle = 2.0f * (F32) atan2(radius, dist);
00408
00409
00410 F32 fraction_of_fov = angle / mView;
00411
00412
00413 return (fraction_of_fov * mViewHeightInPixels);
00414 }
00415 else
00416 {
00417
00418 return -1.0f;
00419 }
00420 }
00421
00422
00423
00424
00425 F32 LLCamera::visibleDistance(const LLVector3 &pos, F32 rad, F32 fudgedist, U32 planemask) const
00426 {
00427 if (mFixedDistance > 0)
00428 {
00429 return mFixedDistance;
00430 }
00431 LLVector3 dvec = pos - mOrigin;
00432
00433 F32 dist = dvec.magVec();
00434 if (dist > rad)
00435 {
00436 F32 dp,tdist;
00437 dp = dvec * mXAxis;
00438 if (dp < -rad)
00439 return -dist;
00440
00441 rad *= fudgedist;
00442 LLVector3 tvec(pos);
00443 for (int p=0; p<PLANE_NUM; p++)
00444 {
00445 if (!(planemask & (1<<p)))
00446 continue;
00447 tdist = -(mWorldPlanes[p].dist(tvec));
00448 if (tdist > rad)
00449 return -dist;
00450 }
00451 }
00452 return dist;
00453 }
00454
00455
00456
00457 F32 LLCamera::visibleHorizDistance(const LLVector3 &pos, F32 rad, F32 fudgedist, U32 planemask) const
00458 {
00459 if (mFixedDistance > 0)
00460 {
00461 return mFixedDistance;
00462 }
00463 LLVector3 dvec = pos - mOrigin;
00464
00465 F32 dist = dvec.magVec();
00466 if (dist > rad)
00467 {
00468 rad *= fudgedist;
00469 LLVector3 tvec(pos);
00470 for (int p=0; p<HORIZ_PLANE_NUM; p++)
00471 {
00472 if (!(planemask & (1<<p)))
00473 continue;
00474 F32 tdist = -(mHorizPlanes[p].dist(tvec));
00475 if (tdist > rad)
00476 return -dist;
00477 }
00478 }
00479 return dist;
00480 }
00481
00482
00483
00484 std::ostream& operator<<(std::ostream &s, const LLCamera &C)
00485 {
00486 s << "{ \n";
00487 s << " Center = " << C.getOrigin() << "\n";
00488 s << " AtAxis = " << C.getXAxis() << "\n";
00489 s << " LeftAxis = " << C.getYAxis() << "\n";
00490 s << " UpAxis = " << C.getZAxis() << "\n";
00491 s << " View = " << C.getView() << "\n";
00492 s << " Aspect = " << C.getAspect() << "\n";
00493 s << " NearPlane = " << C.mNearPlane << "\n";
00494 s << " FarPlane = " << C.mFarPlane << "\n";
00495 s << " TopPlane = " << C.mLocalPlanes[LLCamera::PLANE_TOP][VX] << " "
00496 << C.mLocalPlanes[LLCamera::PLANE_TOP][VY] << " "
00497 << C.mLocalPlanes[LLCamera::PLANE_TOP][VZ] << "\n";
00498 s << " BottomPlane = " << C.mLocalPlanes[LLCamera::PLANE_BOTTOM][VX] << " "
00499 << C.mLocalPlanes[LLCamera::PLANE_BOTTOM][VY] << " "
00500 << C.mLocalPlanes[LLCamera::PLANE_BOTTOM][VZ] << "\n";
00501 s << " LeftPlane = " << C.mLocalPlanes[LLCamera::PLANE_LEFT][VX] << " "
00502 << C.mLocalPlanes[LLCamera::PLANE_LEFT][VY] << " "
00503 << C.mLocalPlanes[LLCamera::PLANE_LEFT][VZ] << "\n";
00504 s << " RightPlane = " << C.mLocalPlanes[LLCamera::PLANE_RIGHT][VX] << " "
00505 << C.mLocalPlanes[LLCamera::PLANE_RIGHT][VY] << " "
00506 << C.mLocalPlanes[LLCamera::PLANE_RIGHT][VZ] << "\n";
00507 s << "}";
00508 return s;
00509 }
00510
00511
00512
00513
00514
00515 void LLCamera::calculateFrustumPlanes()
00516 {
00517
00518
00519
00520
00521
00522
00523 F32 left,right,top,bottom;
00524 top = mFarPlane * (F32)tanf(0.5f * mView);
00525 bottom = -top;
00526 left = top * mAspect;
00527 right = -left;
00528
00529 calculateFrustumPlanes(left, right, top, bottom);
00530 }
00531
00532 LLPlane planeFromPoints(LLVector3 p1, LLVector3 p2, LLVector3 p3)
00533 {
00534 LLVector3 n = ((p2-p1)%(p3-p1));
00535 n.normVec();
00536
00537 return LLPlane(p1, n);
00538 }
00539
00540 U8 LLCamera::calcPlaneMask(const LLPlane& plane)
00541 {
00542 U8 mask = 0;
00543
00544 if (plane.mV[0] >= 0)
00545 {
00546 mask |= 1;
00547 }
00548 if (plane.mV[1] >= 0)
00549 {
00550 mask |= 2;
00551 }
00552 if (plane.mV[2] >= 0)
00553 {
00554 mask |= 4;
00555 }
00556
00557 return mask;
00558 }
00559
00560 void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
00561 {
00562
00563 for (int i = 0; i < 8; i++)
00564 {
00565 mAgentFrustum[i] = frust[i];
00566 }
00567
00568 mFrustumCornerDist = (frust[5] - getOrigin()).magVec();
00569
00570
00571
00572
00573
00574
00575 mAgentPlanes[2].p = planeFromPoints(frust[0], frust[1], frust[2]);
00576
00577
00578 mAgentPlanes[5].p = planeFromPoints(frust[5], frust[4], frust[6]);
00579
00580
00581 mAgentPlanes[0].p = planeFromPoints(frust[4], frust[0], frust[7]);
00582
00583
00584 mAgentPlanes[1].p = planeFromPoints(frust[1], frust[5], frust[6]);
00585
00586
00587 mAgentPlanes[4].p = planeFromPoints(frust[3], frust[2], frust[6]);
00588
00589
00590 mAgentPlanes[3].p = planeFromPoints(frust[1], frust[0], frust[4]);
00591
00592
00593 for (U32 i = 0; i < mPlaneCount; i++)
00594 {
00595 mAgentPlanes[i].mask = calcPlaneMask(mAgentPlanes[i].p);
00596 }
00597 }
00598
00599 void LLCamera::calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom)
00600 {
00601 LLVector3 a, b, c;
00602
00603
00604
00605
00606
00607 a.setVec(0.0f, 0.0f, 0.0f);
00608 b.setVec(mFarPlane, right, top);
00609 c.setVec(mFarPlane, right, bottom);
00610 mLocalPlanes[PLANE_RIGHT].setVec(a, b, c);
00611
00612 c.setVec(mFarPlane, left, top);
00613 mLocalPlanes[PLANE_TOP].setVec(a, c, b);
00614
00615 b.setVec(mFarPlane, left, bottom);
00616 mLocalPlanes[PLANE_LEFT].setVec(a, b, c);
00617
00618 c.setVec(mFarPlane, right, bottom);
00619 mLocalPlanes[PLANE_BOTTOM].setVec( a, c, b);
00620
00621
00622 mFrustCenter = X_AXIS*mFarPlane*0.5f;
00623 mFrustCenter = transformToAbsolute(mFrustCenter);
00624 mFrustRadiusSquared = mFarPlane*0.5f;
00625 mFrustRadiusSquared *= mFrustRadiusSquared * 1.05f;
00626 }
00627
00628
00629 void LLCamera::calculateFrustumPlanesFromWindow(F32 x1, F32 y1, F32 x2, F32 y2)
00630 {
00631 F32 bottom, top, left, right;
00632 F32 view_height = (F32)tanf(0.5f * mView) * mFarPlane;
00633 F32 view_width = view_height * mAspect;
00634
00635 left = x1 * -2.f * view_width;
00636 right = x2 * -2.f * view_width;
00637 bottom = y1 * 2.f * view_height;
00638 top = y2 * 2.f * view_height;
00639
00640 calculateFrustumPlanes(left, right, top, bottom);
00641 }
00642
00643 void LLCamera::calculateWorldFrustumPlanes()
00644 {
00645 F32 d;
00646 LLVector3 center = mOrigin - mXAxis*mNearPlane;
00647 mWorldPlanePos = center;
00648 for (int p=0; p<4; p++)
00649 {
00650 LLVector3 pnorm = LLVector3(mLocalPlanes[p]);
00651 LLVector3 norm = rotateToAbsolute(pnorm);
00652 norm.normVec();
00653 d = -(center * norm);
00654 mWorldPlanes[p] = LLPlane(norm, d);
00655 }
00656
00657 LLVector3 zaxis(0, 0, 1.0f);
00658 F32 yaw = getYaw();
00659 {
00660 LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_LEFT]);
00661 tnorm.rotVec(yaw, zaxis);
00662 d = -(mOrigin * tnorm);
00663 mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d);
00664 }
00665 {
00666 LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_RIGHT]);
00667 tnorm.rotVec(yaw, zaxis);
00668 d = -(mOrigin * tnorm);
00669 mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d);
00670 }
00671 }
00672
00673
00674
00675
00676
00677
00678
00679