void C3dCamera::ReInit() { SetLookAtPos(0.0f, 0.0f, 0.0f); SetEyePos(9.0f, 9.0f, 9.0f); SetFocalLength(9.0f); SetRotationAboutLookAt(-30.0f, 0.0f, -30.0f); SetUpVector(0.0f, 0.0f, 1.0f); // Z-Axis is up m_fPitch = 0.0f; m_fYaw = 0.0f; m_fRoll = 0.0f; m_fFovY = 45.0f; m_fNear = 1.0f; m_fFar = 10000.0f; m_bPerspective = TRUE; m_bBuildLists = TRUE; m_iDisplayLists = 0; m_bResetClippingPlanes = TRUE; // Clear our modelview and projection matrix memset(&m_dModelViewMatrix, 0, sizeof(GLdouble)*16); memset(&m_dProjectionMatrix, 0, sizeof(GLdouble)*16); }
void Camera::Update() { //float dt = TheTimer::Instance()->GetDt(); Vec3f pos; if (m_target) { pos = m_target->GetPos(); // yRotAuto = 0; #ifdef AUTO_ROTATE // Swing behind target float dir = m_target->GetDir() + 180.0f; float angleDiff = yRotAuto - dir; // Rotate to face m_dir, taking the shortest route (CW or CCW) if (fabs(angleDiff) < 0.1f) // TODO CONFIG { yRotAuto = dir; } else { float ROT_SPEED = 1.0f; // TODO CONFIG if (yRotAuto > dir) { yRotAuto -= ROT_SPEED * dt * fabs(angleDiff); } else if (yRotAuto < dir) { yRotAuto += ROT_SPEED * dt * fabs(angleDiff); } } #endif // AUTO_ROTATE #ifdef PORTAL_ROTATE // TODO Get closest portal static PGameObject lastportal = 0; // We want to get the closest portal to the target, even if they have never intersected it. int pid = m_target->GetIgnorePortalId(); if (pid > -1) { lastportal = TheGame::Instance()->GetGameObject(pid); } else { // Look for portals in this room, find closest. // TODO Optimise // just check periodically ? Portals portals = GetPortals(); float bestSqDist = 999999.9f; for (Portals::iterator it = portals.begin(); it != portals.end(); ++it) { Portal* p = *it; float sqDist = (p->GetPos() - pos).SqLen(); if (sqDist < bestSqDist) { bestSqDist = sqDist; lastportal = p; } } } if (lastportal) { float pdist = (pos - lastportal->GetPos()).SqLen(); // sq dist from portal to player static const float MAX_DIST = ROConfig()->GetFloat("portal-max-dist", 200.0f); static const float MAX_SQ_DIST = MAX_DIST * MAX_DIST; if (pdist < MAX_SQ_DIST) { yRotAuto = atan2(-pos.x, pos.z) * (1.0f - pdist / MAX_SQ_DIST); //std::cout << "SQ Dist from portal: " << pdist << " pos.z=" << pos.z << " pos.x=" << pos.x << " yRotAuto degs=" << RadToDeg(yRotAuto) << "\n"; } } #endif // PORTAL_ROTATE } else { pos = posNoTarget; } pos += posOffset; float y = DegToRad(yRotAuto + yRotUser); SetEyePos(Vec3f( pos.x + sin(y) * cos(xRot) * zDist, pos.y + sin(xRot) * zDist, pos.z + cos(y) * cos(xRot) * zDist)); SetLookAtPos(pos); }
void C3dCamera::FitBounds(double minX, double minY, double minZ, double maxX, double maxY,double maxZ) { boundingPlane boundsRight; boundingPlane boundsLeft; boundingPlane boundsTop; boundingPlane boundsBottom; boundingPlane boundsNear; boundingPlane boundsFar; SG_VECTOR boundsMax; SG_VECTOR boundsMin; SG_VECTOR vecCenter; SG_VECTOR vertices[8]; SG_VECTOR vecOffset; sgCMatrix matrix; GLdouble focalLength; GLdouble fDepthWidth, fDepthHeight; GLdouble rx, ry, rz; GLdouble fTan; GLdouble fx, fz; // Initialize our function variables boundsRight.fDepth = 0.0; boundsLeft.fDepth = 0.0; boundsTop.fDepth = 0.0; boundsBottom.fDepth = 0.0; boundsNear.fDepth = 0.0; boundsFar.fDepth = 0.0; memset(&(boundsRight.vec),0,sizeof(SG_VECTOR)); memset(&(boundsLeft.vec),0,sizeof(SG_VECTOR)); memset(&(boundsTop.vec),0,sizeof(SG_VECTOR)); memset(&(boundsBottom.vec),0,sizeof(SG_VECTOR)); memset(&(boundsNear.vec),0,sizeof(SG_VECTOR)); memset(&(boundsFar.vec),0,sizeof(SG_VECTOR)); memset(&(vecOffset),0,sizeof(SG_VECTOR)); memset(&(boundsMin),0,sizeof(SG_VECTOR)); memset(&(boundsMax),0,sizeof(SG_VECTOR)); memset(&(vecCenter),0,sizeof(SG_VECTOR)); fTan = (double)tanf((float)Radiansf(m_fFovY/2)); // Get the cameras rotatiom about the LookAt position, as we // will use this to restore the rotation values after we move // the camera and it's focal length. GetRotationAboutLookAt(&rx, &ry, &rz); // Copy the bounds to our local variable boundsMin.x = minX; boundsMin.y = minY; boundsMin.z = minZ; boundsMax.x = maxX; boundsMax.y = maxY; boundsMax.z = maxZ; double spanX, spanY, spanZ; spanX = Diff(boundsMax.x, boundsMin.x); spanY = Diff(boundsMax.y, boundsMin.y); spanZ = Diff(boundsMax.z, boundsMin.z); vecCenter.x = boundsMax.x - fabs(spanX)/2; vecCenter.y = boundsMax.y - fabs(spanY)/2; vecCenter.z = boundsMax.z - fabs(spanZ)/2; boundsMax.x = spanX/2; boundsMax.y = spanY/2; boundsMax.z = spanZ/2; boundsMin.x = -spanX/2; boundsMin.y = -spanY/2; boundsMin.z = -spanZ/2; // Given the bounding box, fill in the missing vertices to complete our // cube vertices[0] = boundsMax; // Left vertices[1].x = boundsMax.x; vertices[1].y = boundsMax.y; vertices[1].z = boundsMin.x; vertices[2].x = boundsMax.x; vertices[2].y = boundsMin.y; vertices[2].z = boundsMin.x; vertices[3].x = boundsMax.x; vertices[3].y = boundsMin.y; vertices[3].z = boundsMax.x; vertices[4] = boundsMin; vertices[5].x = boundsMin.x; vertices[5].y = boundsMin.y; vertices[5].z = boundsMax.x; vertices[6].x = boundsMin.x; vertices[6].y = boundsMax.y; vertices[6].z = boundsMax.x; vertices[7].x = boundsMin.x; vertices[7].y = boundsMax.y; vertices[7].z = boundsMin.x; // Get the cameras rotation matrix GetRotationMatrix(matrix); for(int i=0; i<8; i++) { // Transform the vertice by the camera rotation matrix. Since we define the // default 'Up' camera position as Z-axis Up, the coordinates map as follows: // X maps to Width, // Y maps to Depth // Z mpas to Height zero_p.x = zero_p.y =zero_p.z =0.0; matrix.ApplyMatrixToVector(zero_p, vertices[i]); // Calculate the focal length needed to fit the near bounding plane fDepthWidth = (fabs(vertices[i].x)/fTan/m_fAspect)-vertices[i].y; fDepthHeight = (fabs(vertices[i].z)/fTan)-vertices[i].y; // Calculate the Near clipping bounds. This will be used to fit Isometric views and // for calculating the Near/Far clipping m_fFrustum. if(vertices[i].y<0) { if( fabs(vertices[i].x) > fabs(boundsNear.vec.x) || (fabs(vertices[i].x) == boundsNear.vec.x && fabs(vertices[i].y) > fabs(boundsNear.vec.z)) ) { boundsNear.vec.x = fabs(vertices[i].x); boundsNear.vec.z = fabs(vertices[i].y); } if( fabs(vertices[i].z) > fabs(boundsNear.vec.y) || (fabs(vertices[i].z) == boundsNear.vec.y) ) { boundsNear.vec.y = fabs(vertices[i].z); //boundsNear.vec[W] = fabs(vertices[i].y); } // Get the bounding depth closest to the viewer if(fDepthWidth < boundsNear.fDepth || boundsNear.fDepth == 0) boundsNear.fDepth = fDepthWidth; if(fDepthHeight < boundsNear.fDepth || boundsNear.fDepth == 0) boundsNear.fDepth = fDepthHeight; } else { if( fabs(vertices[i].x) > fabs(boundsFar.vec.x) || (fabs(vertices[i].x) == boundsFar.vec.x && fabs(vertices[i].y) < fabs(boundsFar.vec.z)) ) { boundsFar.vec.x = vertices[i].x; boundsFar.vec.z = vertices[i].y; } if( fabs(vertices[i].z) > fabs(boundsFar.vec.y) || (fabs(vertices[i].z) == fabs(boundsFar.vec.y)) ) { boundsFar.vec.y = vertices[i].z; //boundsFar.vec[W] = vertices[i].y; } // Get the bounding depth furtherest from the viewer if(fDepthWidth > boundsFar.fDepth) boundsFar.fDepth = fDepthWidth; if(fDepthHeight > boundsFar.fDepth) boundsFar.fDepth = fDepthHeight; } // Calculate the Right, Left, Top and Bottom clipping bounds. This will be used to fit // Perspective views. if(vertices[i].x > 0) { if(fDepthWidth > boundsRight.fDepth) { boundsRight.fDepth = fDepthWidth; boundsRight.vec.x = vertices[i].x; //boundsRight.vec[W] = vertices[i].y; } } if(vertices[i].x <= 0) { if(fDepthWidth > boundsLeft.fDepth) { boundsLeft.fDepth = fDepthWidth; boundsLeft.vec.x = vertices[i].x; //boundsLeft.vec[W] = vertices[i].y; } } if(vertices[i].z > 0) { if(fDepthHeight > boundsTop.fDepth) { boundsTop.fDepth = fDepthHeight; boundsTop.vec.x = vertices[i].x; //boundsTop.vec[W] = vertices[i].y; } } if(vertices[i].z <= 0) { if(fDepthHeight > boundsBottom.fDepth) { boundsBottom.fDepth = fDepthHeight; boundsBottom.vec.x = vertices[i].x; //boundsBottom.vec[W] = vertices[i].y; } } } // Now that we have the view clipping bounds, we can calculate the focal depth // required to fit the volumn and the offset necessary to center the volumn. if(m_bPerspective) { sgCMatrix invMatrix; if(boundsRight.fDepth == boundsLeft.fDepth && boundsTop.fDepth == boundsBottom.fDepth ) { // Front, Side or Top view // Since the bounds are symetric, just use the Right and Top focal depth. fx = boundsRight.fDepth; fz = boundsTop.fDepth; // No offset necessary vecOffset.x = vecOffset.y = vecOffset.z = 0.0; } else { // Calculate the average focal length needed to fit the bounding box fx = (boundsRight.fDepth + boundsLeft.fDepth)/2; fz = (boundsTop.fDepth + boundsBottom.fDepth)/2; // Calculate the offset necessary to center the bounding box. Note that we // use a scaling factor for centering the non-limiting bounds to achieve a // more visually appealing center. if(fx > fz) { GLdouble fScale = sqrt(boundsTop.fDepth/boundsBottom.fDepth); GLdouble fTop = fTan*fx - fTan*boundsTop.fDepth; GLdouble fBottom = fTan*fx - fTan*boundsBottom.fDepth; vecOffset.x = (fTan*m_fAspect*boundsRight.fDepth - fTan*m_fAspect*fx); vecOffset.z = (fBottom-fTop*fScale)/2; } else { GLdouble fScale = sqrt(boundsLeft.fDepth/boundsRight.fDepth); GLdouble fRight = fTan*m_fAspect*fz - fTan*m_fAspect*boundsRight.fDepth; GLdouble fLeft = fTan*m_fAspect*fz - fTan*m_fAspect*boundsLeft.fDepth; vecOffset.z = (fTan*boundsTop.fDepth - fTan*fz); vecOffset.x = (fLeft - fRight*fScale)/2; } } // Now that we have the offsets necessary to center the bounds, we must rotate // the vertices (camera coordinates) by the cameras inverse rotation matrix to // convert the offsets to world coordinates. GetInvRotationMatrix(invMatrix); zero_p.x = zero_p.y =zero_p.z =0.0; invMatrix.ApplyMatrixToVector(zero_p,vecOffset); } else { // Isometric View // Calculate the focal length needed to fit the near bounding plane if(m_iScreenWidth <= m_iScreenHeight) { fx = boundsNear.vec.x/tanf((float)Radiansf(m_fFovY/2)); fz = boundsNear.vec.y/tanf((float)Radiansf(m_fFovY/2))/((GLdouble)m_iScreenHeight/(GLdouble)m_iScreenWidth); } else { fx = boundsNear.vec.x/tanf((float)Radiansf(m_fFovY/2))/m_fAspect; fz = boundsNear.vec.y/tanf((float)Radiansf(m_fFovY/2)); } } // Set the focal length equal to the largest length required to fit either the // Width (Horizontal) or Height (Vertical) focalLength = (fx > fz? fx : fz); // Set the camera's new LookAt position to focus on the center // of the bounding box. SetLookAtPos(vecCenter.x+vecOffset.x, vecCenter.y+vecOffset.y, vecCenter.z+vecOffset.z); // Set the camera focal Length if(focalLength > m_fNear) SetFocalLength(focalLength, TRUE); // Adjust the Near clipping plane if necessary // if((boundsNear.fDepth/2) > 0.5f) // m_fNear = boundsNear.fDepth/2; // Adjust the Far clipping plane if necessary if(focalLength+boundsFar.fDepth > m_fFar) m_fFar = focalLength+boundsFar.fDepth; // Recalculate the camera view m_fFrustum; ResetView(); // Restore the cameras rotation about the LookAt position SetRotationAboutLookAt(rx, ry, rz); }