//----------------------------------------------------------------------- bool Frustum::isVisible(const Vector3& vert, FrustumPlane* culledBy) const { // 对视锥体进行必要的更新 updateFrustumPlanes(); // 遍历视锥体的每个平面,对每个平面, 见如果所有的点都在反面 // 如果这样,对象不可见 for (int plane = 0; plane < 6; ++plane) { // 如果视锥体无限,跳过远裁平面 if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0) continue; if (mFrustumPlanes[plane].getSide(vert) == Plane::NEGATIVE_SIDE) { // 所有的角都在反面,那么在视域之外 if (culledBy) *culledBy = (FrustumPlane)plane; return false; } } return true; }
//----------------------------------------------------------------------- bool Frustum::isVisible(const Sphere& sphere, FrustumPlane* culledBy) const { updateFrustumPlanes(); // 遍历视锥体的每个平面,对每个平面, 见如果所有的点都在反面 // 如果这样,对象不可见 for (int plane = 0; plane < 6; ++plane) { // 如果视锥体空间无限,跳过 if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0) continue; // 如果球体中心到平面的距离为负,并且大于球体半径,那么球在视锥体之外 if (mFrustumPlanes[plane].getDistance(sphere.getCenter()) < -sphere.getRadius()) { // 所有的角在反面,那么不在视野 if (culledBy) *culledBy = (FrustumPlane)plane; return false; } } return true; }
//----------------------------------------------------------------------- bool Frustum::isVisible(const Sphere& sphere, FrustumPlane* culledBy) const { // Make any pending updates to the calculated frustum planes updateFrustumPlanes(); // For each plane, see if sphere is on negative side // If so, object is not visible for (int plane = 0; plane < 6; ++plane) { // Skip far plane if infinite view frustum if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0) continue; // If the distance from sphere center to plane is negative, and 'more negative' // than the radius of the sphere, sphere is outside frustum if (mFrustumPlanes[plane].getDistance(sphere.getCenter()) < -sphere.getRadius()) { // ALL corners on negative side therefore out of view if (culledBy) *culledBy = (FrustumPlane)plane; return false; } } return true; }
//----------------------------------------------------------------------- const Plane* Frustum::getFrustumPlanes(void) const { // 使任何未发生的更新这个视锥体平面发生更新 updateFrustumPlanes(); return mFrustumPlanes; }
// this version checks against extra culling planes bool PCZCamera::isVisible( const AxisAlignedBox &bound, FrustumPlane *culledBy) const { // Null boxes always invisible if ( bound.isNull() ) return false; // Make any pending updates to the calculated frustum planes updateFrustumPlanes(); // check extra culling planes bool extraResults; extraResults = mExtraCullingFrustum.isVisible(bound); if (!extraResults) { return false; } // check "regular" camera frustum bool regcamresults = Camera::isVisible(bound, culledBy); if (!regcamresults) { // culled by regular culling planes return regcamresults; } return true; }
//----------------------------------------------------------------------- bool Frustum::isVisible(const Vector3& vert, FrustumPlane* culledBy) const { // Make any pending updates to the calculated frustum planes updateFrustumPlanes(); // For each plane, see if all points are on the negative side // If so, object is not visible for (int plane = 0; plane < 6; ++plane) { // Skip far plane if infinite view frustum if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0) continue; if (mFrustumPlanes[plane].getSide(vert) == Plane::NEGATIVE_SIDE) { // ALL corners on negative side therefore out of view if (culledBy) *culledBy = (FrustumPlane)plane; return false; } } return true; }
//----------------------------------------------------------------------- const Plane* Frustum::getFrustumPlanes(void) const { // Make any pending updates to the calculated frustum planes updateFrustumPlanes(); return mFrustumPlanes; }
//----------------------------------------------------------------------- const Plane& Frustum::getFrustumPlane(unsigned short plane) const { // 使任何未发生的更新这个视锥体平面发生更新 updateFrustumPlanes(); return mFrustumPlanes[plane]; }
//----------------------------------------------------------------------- const Plane& Frustum::getFrustumPlane(unsigned short plane) const { // Make any pending updates to the calculated frustum planes updateFrustumPlanes(); return mFrustumPlanes[plane]; }
PlaneBoundedVolume Frustum::getPlaneBoundedVolume() { updateFrustumPlanes(); PlaneBoundedVolume volume; volume.planes.push_back(mFrustumPlanes[FRUSTUM_PLANE_NEAR]); volume.planes.push_back(mFrustumPlanes[FRUSTUM_PLANE_FAR]); volume.planes.push_back(mFrustumPlanes[FRUSTUM_PLANE_BOTTOM]); volume.planes.push_back(mFrustumPlanes[FRUSTUM_PLANE_TOP]); volume.planes.push_back(mFrustumPlanes[FRUSTUM_PLANE_LEFT]); volume.planes.push_back(mFrustumPlanes[FRUSTUM_PLANE_RIGHT]); return volume; }
//----------------------------------------------------------------------- bool Frustum::isVisible(const AxisAlignedBox& bound, FrustumPlane* culledBy) const { // AABB盒子是个空盒子,不可见 if (bound.isNull()) return false; // AABB盒子无限大 if (bound.isInfinite()) return true; // 进行必要的更新 updateFrustumPlanes(); // 获取AABB盒子的中心 Vector3 centre = bound.getCenter(); // 获取盒子半大小向量 Vector3 halfSize = bound.getHalfSize(); // 遍历视锥体的每个平面,对每个平面, 见如果所有的点都在反面 // 如果这样,对象不可见 for (int plane = 0; plane < 6; ++plane) { // 如果视锥体无限,跳过远裁平面 if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0) continue; Plane::Side side = mFrustumPlanes[plane].getSide(centre, halfSize); if (side == Plane::NEGATIVE_SIDE) { // 所有的角都在反面,那么在视域之外 if (culledBy) *culledBy = (FrustumPlane)plane; return false; } } return true; }
//----------------------------------------------------------------------- bool Frustum::isVisible(const AxisAlignedBox& bound, FrustumPlane* culledBy) const { // Null boxes always invisible if (bound.isNull()) return false; // Infinite boxes always visible if (bound.isInfinite()) return true; // Make any pending updates to the calculated frustum planes updateFrustumPlanes(); // Get centre of the box Vector3 centre = bound.getCenter(); // Get the half-size of the box Vector3 halfSize = bound.getHalfSize(); // For each plane, see if all points are on the negative side // If so, object is not visible for (int plane = 0; plane < 6; ++plane) { // Skip far plane if infinite view frustum if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0) continue; Plane::Side side = mFrustumPlanes[plane].getSide(centre, halfSize); if (side == Plane::NEGATIVE_SIDE) { // ALL corners on negative side therefore out of view if (culledBy) *culledBy = (FrustumPlane)plane; return false; } } return true; }
//---------------------------------------------------------------------() void Camera::getCameraToViewportBoxVolume(Real screenLeft, Real screenTop, Real screenRight, Real screenBottom, PlaneBoundedVolume* outVolume, bool includeFarPlane) { outVolume->planes.clear(); if (mProjType == PT_PERSPECTIVE) { // Use the corner rays to generate planes Ray ul = getCameraToViewportRay(screenLeft, screenTop); Ray ur = getCameraToViewportRay(screenRight, screenTop); Ray bl = getCameraToViewportRay(screenLeft, screenBottom); Ray br = getCameraToViewportRay(screenRight, screenBottom); Vector3 normal; // top plane normal = ul.getDirection().crossProduct(ur.getDirection()); normal.normalise(); outVolume->planes.push_back( Plane(normal, getDerivedPosition())); // right plane normal = ur.getDirection().crossProduct(br.getDirection()); normal.normalise(); outVolume->planes.push_back( Plane(normal, getDerivedPosition())); // bottom plane normal = br.getDirection().crossProduct(bl.getDirection()); normal.normalise(); outVolume->planes.push_back( Plane(normal, getDerivedPosition())); // left plane normal = bl.getDirection().crossProduct(ul.getDirection()); normal.normalise(); outVolume->planes.push_back( Plane(normal, getDerivedPosition())); } else { // ortho planes are parallel to frustum planes Ray ul = getCameraToViewportRay(screenLeft, screenTop); Ray br = getCameraToViewportRay(screenRight, screenBottom); updateFrustumPlanes(); outVolume->planes.push_back( Plane(mFrustumPlanes[FRUSTUM_PLANE_TOP].normal, ul.getOrigin())); outVolume->planes.push_back( Plane(mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal, br.getOrigin())); outVolume->planes.push_back( Plane(mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal, br.getOrigin())); outVolume->planes.push_back( Plane(mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal, ul.getOrigin())); } // near & far plane applicable to both projection types outVolume->planes.push_back(getFrustumPlane(FRUSTUM_PLANE_NEAR)); if (includeFarPlane) outVolume->planes.push_back(getFrustumPlane(FRUSTUM_PLANE_FAR)); }
void LLViewerCamera::setPerspective(BOOL for_selection, S32 x, S32 y_from_bot, S32 width, S32 height, BOOL limit_select_distance, F32 z_near, F32 z_far) { F32 fov_y, aspect; fov_y = RAD_TO_DEG * getView(); BOOL z_default_near, z_default_far = FALSE; if (z_far <= 0) { z_default_far = TRUE; z_far = getFar(); } if (z_near <= 0) { z_default_near = TRUE; z_near = getNear(); } aspect = getAspect(); // Load camera view matrix glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glh::matrix4f proj_mat; if (for_selection) { // make a tiny little viewport // anything drawn into this viewport will be "selected" GLint viewport[4]; viewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; viewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; viewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); viewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); proj_mat = gl_pick_matrix(x+width/2.f, y_from_bot+height/2.f, (GLfloat) width, (GLfloat) height, viewport); if (limit_select_distance) { // ...select distance from control z_far = gSavedSettings.getF32("MaxSelectDistance"); } else { z_far = gAgent.mDrawDistance; } } else { // Only override the far clip if it's not passed in explicitly. if (z_default_far) { z_far = MAX_FAR_CLIP; } glViewport(x, y_from_bot, width, height); gGLViewport[0] = x; gGLViewport[1] = y_from_bot; gGLViewport[2] = width; gGLViewport[3] = height; } if (mZoomFactor > 1.f) { float offset = mZoomFactor - 1.f; int pos_y = mZoomSubregion / llceil(mZoomFactor); int pos_x = mZoomSubregion - (pos_y*llceil(mZoomFactor)); glh::matrix4f translate; translate.set_translate(glh::vec3f(offset - (F32)pos_x * 2.f, offset - (F32)pos_y * 2.f, 0.f)); glh::matrix4f scale; scale.set_scale(glh::vec3f(mZoomFactor, mZoomFactor, 1.f)); proj_mat = scale*proj_mat; proj_mat = translate*proj_mat; } calcProjection(z_far); // Update the projection matrix cache proj_mat *= gl_perspective(fov_y,aspect,z_near,z_far); glLoadMatrixf(proj_mat.m); for (U32 i = 0; i < 16; i++) { gGLProjection[i] = proj_mat.m[i]; } glMatrixMode( GL_MODELVIEW ); glh::matrix4f modelview((GLfloat*) OGL_TO_CFR_ROTATION); GLfloat ogl_matrix[16]; getOpenGLTransform(ogl_matrix); modelview *= glh::matrix4f(ogl_matrix); glLoadMatrixf(modelview.m); if (for_selection && (width > 1 || height > 1)) { // NB: as of this writing, i believe the code below is broken (doesn't take into account the world view, assumes entire window) // however, it is also unused (the GL matricies are used for selection, (see LLCamera::sphereInFrustum())) and so i'm not // comfortable hacking on it. calculateFrustumPlanesFromWindow((F32)(x - width / 2) / (F32)gViewerWindow->getWindowWidthScaled() - 0.5f, (F32)(y_from_bot - height / 2) / (F32)gViewerWindow->getWindowHeightScaled() - 0.5f, (F32)(x + width / 2) / (F32)gViewerWindow->getWindowWidthScaled() - 0.5f, (F32)(y_from_bot + height / 2) / (F32)gViewerWindow->getWindowHeightScaled() - 0.5f); } // if not picking and not doing a snapshot, cache various GL matrices if (!for_selection && mZoomFactor == 1.f) { // Save GL matrices for access elsewhere in code, especially project_world_to_screen //glGetDoublev(GL_MODELVIEW_MATRIX, gGLModelView); for (U32 i = 0; i < 16; i++) { gGLModelView[i] = modelview.m[i]; } } updateFrustumPlanes(*this); /*if (gSavedSettings.getBOOL("CameraOffset")) { glMatrixMode(GL_PROJECTION); glTranslatef(0,0,-50); glRotatef(20.0,1,0,0); glMatrixMode(GL_MODELVIEW); }*/ }
void LLViewerCamera::setPerspective(BOOL for_selection, S32 x, S32 y_from_bot, S32 width, S32 height, BOOL limit_select_distance, F32 z_near, F32 z_far) { F32 fov_y, aspect; fov_y = RAD_TO_DEG * getView(); BOOL z_default_far = FALSE; if (z_far <= 0) { z_default_far = TRUE; z_far = getFar(); } if (z_near <= 0) { z_near = getNear(); } aspect = getAspect(); // Load camera view matrix gGL.matrixMode( LLRender::MM_PROJECTION ); gGL.loadIdentity(); LLMatrix4a proj_mat; proj_mat.setIdentity(); if (for_selection) { // make a tiny little viewport // anything drawn into this viewport will be "selected" const LLRect& rect = gViewerWindow->getWorldViewRectRaw(); const F32 scale_x = rect.getWidth() / F32(width); const F32 scale_y = rect.getHeight() / F32(height); const F32 trans_x = scale_x + (2.f * (rect.mLeft - x)) / F32(width) - 1.f; const F32 trans_y = scale_y + (2.f * (rect.mBottom - y_from_bot)) / F32(height) - 1.f; //Generate a pick matrix proj_mat.applyScale_affine(scale_x, scale_y, 1.f); proj_mat.setTranslate_affine(LLVector3(trans_x, trans_y, 0.f)); if (limit_select_distance) { // ...select distance from control // z_far = gSavedSettings.getF32("MaxSelectDistance"); // [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e z_far = (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) ? gSavedSettings.getF32("MaxSelectDistance") : 1.5; // [/RLVa:KB] } else { z_far = gAgentCamera.mDrawDistance; } } else { // Only override the far clip if it's not passed in explicitly. if (z_default_far) { z_far = MAX_FAR_CLIP; } glViewport(x, y_from_bot, width, height); gGLViewport[0] = x; gGLViewport[1] = y_from_bot; gGLViewport[2] = width; gGLViewport[3] = height; } if (mZoomFactor > 1.f) { float offset = mZoomFactor - 1.f; int pos_y = mZoomSubregion / llceil(mZoomFactor); int pos_x = mZoomSubregion - (pos_y*llceil(mZoomFactor)); proj_mat.applyTranslation_affine(offset - (F32)pos_x * 2.f, offset - (F32)pos_y * 2.f, 0.f); proj_mat.applyScale_affine(mZoomFactor,mZoomFactor,1.f); } calcProjection(z_far); // Update the projection matrix cache proj_mat.mul(gGL.genPersp(fov_y,aspect,z_near,z_far)); gGL.loadMatrix(proj_mat); gGLProjection = proj_mat; gGL.matrixMode(LLRender::MM_MODELVIEW ); LLMatrix4a ogl_matrix; getOpenGLTransform(ogl_matrix.getF32ptr()); LLMatrix4a modelview; modelview.setMul(OGL_TO_CFR_ROTATION, ogl_matrix); gGL.loadMatrix(modelview); if (for_selection && (width > 1 || height > 1)) { // NB: as of this writing, i believe the code below is broken (doesn't take into account the world view, assumes entire window) // however, it is also unused (the GL matricies are used for selection, (see LLCamera::sphereInFrustum())) and so i'm not // comfortable hacking on it. calculateFrustumPlanesFromWindow((F32)(x - width / 2) / (F32)gViewerWindow->getWindowWidthScaled() - 0.5f, (F32)(y_from_bot - height / 2) / (F32)gViewerWindow->getWindowHeightScaled() - 0.5f, (F32)(x + width / 2) / (F32)gViewerWindow->getWindowWidthScaled() - 0.5f, (F32)(y_from_bot + height / 2) / (F32)gViewerWindow->getWindowHeightScaled() - 0.5f); } // if not picking and not doing a snapshot, cache various GL matrices if (!for_selection && mZoomFactor == 1.f) { // Save GL matrices for access elsewhere in code, especially project_world_to_screen //glGetDoublev(GL_MODELVIEW_MATRIX, gGLModelView); glh_set_current_modelview(modelview); } updateFrustumPlanes(*this); /*if (gSavedSettings.getBOOL("CameraOffset")) { gGL.matrixMode(LLRender::MM_PROJECTION); gGL.translatef(0,0,-50); gGL.rotatef(20.0,1,0,0); gGL.matrixMode(LLRender::MM_MODELVIEW); }*/ }
void kore::Camera::paramsChanged() { _matViewProj = _matProjection * _matView; updateFrustumPlanes(); }