void LLCamera::setNear(F32 near_plane) { mNearPlane = near_plane; if (mNearPlane < MIN_NEAR_PLANE) { mNearPlane = MIN_NEAR_PLANE; } else if (mNearPlane > MAX_NEAR_PLANE) { mNearPlane = MAX_NEAR_PLANE; } calculateFrustumPlanes(); }
void LLCamera::setView(F32 field_of_view) { mView = field_of_view; if (mView < MIN_FIELD_OF_VIEW) { mView = MIN_FIELD_OF_VIEW; } else if (mView > MAX_FIELD_OF_VIEW) { mView = MAX_FIELD_OF_VIEW; } calculateFrustumPlanes(); }
LLCamera::LLCamera(F32 z_field_of_view, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane) : LLCoordFrame(), mView(z_field_of_view), mAspect(aspect_ratio), mViewHeightInPixels(view_height_in_pixels), mNearPlane(near_plane), mFarPlane(far_plane), mFixedDistance(-1.f), mPlaneCount(6) { if (mView < MIN_FIELD_OF_VIEW) { mView = MIN_FIELD_OF_VIEW; } else if (mView > MAX_FIELD_OF_VIEW) { mView = MAX_FIELD_OF_VIEW; } if (mAspect < MIN_ASPECT_RATIO) { mAspect = MIN_ASPECT_RATIO; } else if (mAspect > MAX_ASPECT_RATIO) { mAspect = MAX_ASPECT_RATIO; } if (mNearPlane < MIN_NEAR_PLANE) { mNearPlane = MIN_NEAR_PLANE; } else if (mNearPlane > MAX_NEAR_PLANE) { mNearPlane = MAX_NEAR_PLANE; } if (mFarPlane < 0) { mFarPlane = DEFAULT_FAR_PLANE; } else if (mFarPlane < MIN_FAR_PLANE) { mFarPlane = MIN_FAR_PLANE; } else if (mFarPlane > MAX_FAR_PLANE) { mFarPlane = MAX_FAR_PLANE; } calculateFrustumPlanes(); }
void LLCamera::setFar(F32 far_plane) { mFarPlane = far_plane; if (mFarPlane < MIN_FAR_PLANE) { mFarPlane = MIN_FAR_PLANE; } else if (mFarPlane > MAX_FAR_PLANE) { mFarPlane = MAX_FAR_PLANE; } calculateFrustumPlanes(); }
void LLCamera::setViewHeightInPixels(S32 height) { mViewHeightInPixels = height; // Don't really need to do this, but update the pixel meter ratio with it. calculateFrustumPlanes(); }
void LLCamera::setAspect(F32 aspect_ratio) { mAspect = aspect_ratio; if (mAspect < MIN_ASPECT_RATIO) { mAspect = MIN_ASPECT_RATIO; } else if (mAspect > MAX_ASPECT_RATIO) { mAspect = MAX_ASPECT_RATIO; } calculateFrustumPlanes(); }
bool Camera::update() { if ((!dirty) && equal(posSpeed, 0.0f) && equal(rotSpeed, 0.0f)) return false; while (rot.x > rotationAngleClamp) rot.x -= rotationAngleClamp; while (rot.x < -rotationAngleClamp) rot.x += rotationAngleClamp; while (rot.y > rotationAngleClamp) rot.y -= rotationAngleClamp; while (rot.y < -rotationAngleClamp) rot.y += rotationAngleClamp; float dT = RunTime::getLastFrameTime(); glm::vec2 newRot = rot + rotSpeed * dT; if ((newRot.y > -rotationAngleVertMax) && (newRot.y < rotationAngleVertMax)) rot = newRot; else rotSpeed = glm::vec2(0.0f, 0.0f); static glm::quat quatZ = glm::angleAxis(glm::pi<float>(), glm::vec3(0.0f, 0.0f, 1.0f)); glm::quat quatY = glm::angleAxis(rot.x, glm::vec3(0.0f, 1.0f, 0.0f)); glm::quat quatX = glm::angleAxis(rot.y, glm::vec3(1.0f, 0.0f, 0.0f)); glm::quat quaternion = quatZ * quatY * quatX; float factor = movingFaster ? runFactor : 1.0f; glm::vec3 clampedSpeed = posSpeed * factor; if (glm::length(clampedSpeed) > (maxSpeed * factor)) { clampedSpeed = glm::normalize(clampedSpeed) * maxSpeed * factor; } glm::vec3 newPos = pos + (quaternion * clampedSpeed * dT); if (keepInRoom) { if ((room < 0) || (room >= World::sizeRoom())) { keepInRoom = false; pos = newPos; } else if (World::getRoom(room).getBoundingBox().inBox(newPos)) { pos = newPos; } } else { pos = newPos; } glm::mat4 translate = glm::translate(glm::mat4(1.0f), pos); glm::mat4 rotate = glm::toMat4(quaternion); view = glm::inverse(translate * rotate); if (updateViewFrustum) calculateFrustumPlanes(); glm::vec3 at(0.0f, 0.0f, -1.0f); glm::vec3 up(0.0f, -1.0f, 0.0f); Sound::listenAt(pos, quaternion * at, quaternion * up); dirty = false; return updateViewFrustum; }
LLCamera::LLCamera() : LLCoordFrame(), mView(DEFAULT_FIELD_OF_VIEW), mAspect(DEFAULT_ASPECT_RATIO), mViewHeightInPixels( -1 ), // invalid height mNearPlane(DEFAULT_NEAR_PLANE), mFarPlane(DEFAULT_FAR_PLANE), mFixedDistance(-1.f) { calculateFrustumPlanes(); }
// x and y are in WINDOW space, so x = Y-Axis (left/right), y= Z-Axis(Up/Down) void LLCamera::calculateFrustumPlanesFromWindow(F32 x1, F32 y1, F32 x2, F32 y2) { F32 bottom, top, left, right; F32 view_height = (F32)tanf(0.5f * mView) * mFarPlane; F32 view_width = view_height * mAspect; left = x1 * -2.f * view_width; right = x2 * -2.f * view_width; bottom = y1 * 2.f * view_height; top = y2 * 2.f * view_height; calculateFrustumPlanes(left, right, top, bottom); }
void LLCamera::calculateFrustumPlanes() { // The planes only change when any of the frustum descriptions change. // They are not affected by changes of the position of the Frustum // because they are known in the view frame and the position merely // provides information on how to get from the absolute frame to the // view frame. F32 left,right,top,bottom; top = mFarPlane * (F32)tanf(0.5f * mView); bottom = -top; left = top * mAspect; right = -left; calculateFrustumPlanes(left, right, top, bottom); }
void LLCamera::setFar(F32 far_plane) { mFarPlane = llclamp(far_plane, MIN_FAR_PLANE, MAX_FAR_PLANE); calculateFrustumPlanes(); }
void LLCamera::setNear(F32 near_plane) { mNearPlane = llclamp(near_plane, MIN_NEAR_PLANE, MAX_NEAR_PLANE); calculateFrustumPlanes(); }
void LLCamera::setAspect(F32 aspect_ratio) { mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO); calculateFrustumPlanes(); }
void LLCamera::setView(F32 vertical_fov_rads) { mView = llclamp(vertical_fov_rads, MIN_FIELD_OF_VIEW, MAX_FIELD_OF_VIEW); calculateFrustumPlanes(); }
void ofApp::draw(){ ofBackground(ofFloatColor(0.23)); ofSetColor(ofColor::white); ofNoFill(); ofEnableDepthTest(); mCam[activeCam].begin(); { ofSetColor(ofColor::white); vector<ofVec4f> frustumPlanes = calculateFrustumPlanes(mCam[0].getProjectionMatrix()); // we could erase the 3rd element, that is the far plane, // therefore we are testing against an infinitely far frustum, // that is, an open frustum in view direction. // frustumPlanes.erase(frustumPlanes.begin() + 2); ofMatrix4x4 mvm = mCam[0].getModelViewMatrix(); for (auto & s : spheres){ // --- note that we have to transform the sphere centres to the eye space of our frustum culling camera manually, ofVec3f sInEyeSpace = s.getGlobalPosition() * mvm; s.inFrustum = getInFrustum(frustumPlanes, sInEyeSpace, s.radius); } // ----------- // let's count the number of spheres within the frustum of camera 0: mCountInFrustum = 0; for(auto & s : spheres){ s.draw(); if (s.inFrustum) ++ mCountInFrustum; } if (activeCam == 1) { // let's draw the frustum of camera 0 // but first, draw a stand-in for the actual camera. // this will draw a cube and an axis representation where the other camera sits. mCam[0].draw(); // get the camera's near and far plane distance values. float nearC = mCam[0].getNearClip(); float farC = mCam[0].getFarClip(); // Now comes the tricky bit: we want to draw the frustum where camera 0 sits. // Therefore, we move to camera 0 eye space, And draw the frustum fron there. ofPushMatrix(); // we are currently in world space. ofMultMatrix(mCam[0].getModelViewMatrix().getInverse()); // we are now in camera2 view space! // where the origin is at camera2's global position. // draw the frustum in yellow, wireframe ofSetColor(ofColor::yellow); // we want to draw the frustum of camera 0. to do this, we grab the matrix that transforms // from view space into clip space (i.e. the projection matrix) // then we take our unit clip cube (i.e. the cube that delimits clip space) // (this cube is defined to be +-1 into each x, y , z) // and transform it back into view space. We transform it back into // viewspace by applying the inverse transform viewspace -> clipspace // which is the inverse of applying the projection matrix, which is applying // the inverse projection matrix. // so first, grab camera 0's inverse projection matrix: ofMatrix4x4 projectionMatrixInverse = mCam[0].getProjectionMatrix().getInverse(); // the edges of our unit cube in clip space: ofVec3f clipCube[8] = { ofVec3f(-1,-1,-1), ofVec3f(-1, 1,-1), ofVec3f( 1,-1,-1), ofVec3f( 1, 1,-1), ofVec3f(-1,-1, 1), ofVec3f(-1, 1, 1), ofVec3f( 1,-1, 1), ofVec3f( 1, 1, 1), }; // since the clip cube is expressed in clip (=projection) space, we want this // transformed back into our current space, view space, i.e. apply the inverse // projection matrix to it. for (int i =0; i<8; i++){ clipCube[i] = clipCube[i] * projectionMatrixInverse; } // now draw our clip cube side edge rays - note that since the coordinates are // now in world space, we can draw them without applying any additional trans- // formations. for (int i=0;i<4;i++){ ofLine(clipCube[i],clipCube[i+4]); } //// draw the clip cube cap ofRect(clipCube[0],clipCube[3].x-clipCube[0].x,clipCube[3].y-clipCube[0].y); ofRect(clipCube[4],clipCube[7].x-clipCube[4].x,clipCube[7].y-clipCube[4].y); ofPopMatrix(); // and back to world space! } } mCam[activeCam].end(); ofDrawBitmapStringHighlight( "Active Cam: "+ ofToString(activeCam,4,' ') + "\n" + "Visible spheres: "+ ofToString(mCountInFrustum,4,' ') + "\n" + "Press 'c' to switch cameras.", 200, 20); }