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