示例#1
0
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);
}
示例#2
0
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);
}
示例#3
0
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);
}