Beispiel #1
0
void KX_Camera::ExtractFrustumSphere()
{
	if (m_set_frustum_center)
		return;

	// compute sphere for the general case and not only symmetric frustum:
	// the mirror code in ImageRender can use very asymmetric frustum.
	// We will put the sphere center on the line that goes from origin to the center of the far clipping plane
	// This is the optimal position if the frustum is symmetric or very asymmetric and probably close
	// to optimal for the general case. The sphere center position is computed so that the distance to
	// the near and far extreme frustum points are equal.

	// get the transformation matrix from device coordinate to camera coordinate
	MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix;
	clip_camcs_matrix.invert();

	if (m_projection_matrix[3][3] == MT_Scalar(0.0))
	{
		// frustrum projection
		// detect which of the corner of the far clipping plane is the farthest to the origin
		MT_Vector4 nfar;    // far point in device normalized coordinate
		MT_Point3 farpoint; // most extreme far point in camera coordinate
		MT_Point3 nearpoint;// most extreme near point in camera coordinate
		MT_Point3 farcenter(0.0, 0.0, 0.0);// center of far cliping plane in camera coordinate
		MT_Scalar F=-1.0, N; // square distance of far and near point to origin
		MT_Scalar f, n;     // distance of far and near point to z axis. f is always > 0 but n can be < 0
		MT_Scalar e, s;     // far and near clipping distance (<0)
		MT_Scalar c;        // slope of center line = distance of far clipping center to z axis / far clipping distance
		MT_Scalar z;        // projection of sphere center on z axis (<0)
		// tmp value
		MT_Vector4 npoint(1.0, 1.0, 1.0, 1.0);
		MT_Vector4 hpoint;
		MT_Point3 point;
		MT_Scalar len;
		for (int i=0; i<4; i++)
		{
			hpoint = clip_camcs_matrix*npoint;
			point.setValue(hpoint[0]/hpoint[3], hpoint[1]/hpoint[3], hpoint[2]/hpoint[3]);
			len = point.dot(point);
			if (len > F)
			{
				nfar = npoint;
				farpoint = point;
				F = len;
			}
			// rotate by 90 degree along the z axis to walk through the 4 extreme points of the far clipping plane
			len = npoint[0];
			npoint[0] = -npoint[1];
			npoint[1] = len;
			farcenter += point;
		}
		// the far center is the average of the far clipping points
		farcenter *= 0.25;
		// the extreme near point is the opposite point on the near clipping plane
		nfar.setValue(-nfar[0], -nfar[1], -1.0, 1.0);
		nfar = clip_camcs_matrix*nfar;
		nearpoint.setValue(nfar[0]/nfar[3], nfar[1]/nfar[3], nfar[2]/nfar[3]);
		// this is a frustrum projection
		N = nearpoint.dot(nearpoint);
		e = farpoint[2];
		s = nearpoint[2];
		// projection on XY plane for distance to axis computation
		MT_Point2 farxy(farpoint[0], farpoint[1]);
		// f is forced positive by construction
		f = farxy.length();
		// get corresponding point on the near plane
		farxy *= s/e;
		// this formula preserve the sign of n
		n = f*s/e - MT_Point2(nearpoint[0]-farxy[0], nearpoint[1]-farxy[1]).length();
		c = MT_Point2(farcenter[0], farcenter[1]).length()/e;
		// the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case
		z = (F-N)/(2.0*(e-s+c*(f-n)));
		m_frustum_center = MT_Point3(farcenter[0]*z/e, farcenter[1]*z/e, z);
		m_frustum_radius = m_frustum_center.distance(farpoint);
	}
	else
	{
		// orthographic projection
		// The most extreme points on the near and far plane. (normalized device coords)
		MT_Vector4 hnear(1.0, 1.0, 1.0, 1.0), hfar(-1.0, -1.0, -1.0, 1.0);
		
		// Transform to hom camera local space
		hnear = clip_camcs_matrix*hnear;
		hfar = clip_camcs_matrix*hfar;
		
		// Tranform to 3d camera local space.
		MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]);
		MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]);
		
		// just use mediant point
		m_frustum_center = (farpoint + nearpoint)*0.5;
		m_frustum_radius = m_frustum_center.distance(farpoint);
	}
	// Transform to world space.
	m_frustum_center = GetCameraToWorld()(m_frustum_center);
	m_frustum_radius /= fabs(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]);
	
	m_set_frustum_center = true;
}
Beispiel #2
0
// render the scene
void render()
   {
   double delta,idle;

   double elev,dist;

   double coef;

   double light;
   miniv3d lightdir;

   if (winwidth<=0 || winheight<=0) return;

   // update eye point:

   cam->move_back(-speed/params->fps);

   elev=cam->get_elev();
   dist=cam->get_dist();

   // update eye movement:

   speed+=accel*(topspeed-speed);
   if (dabs(speed)<minspeed) speed=0.0;

   cam->rotate_right(accel*turn);
   turn*=(1.0-accel);

   cam->rotate_up(-accel*incline);
   incline*=(1.0-accel);

   cam->rotate_limit(-90.0,90.0);

   coef=dist/hover-1.0;
   if (coef>1.0) coef=1.0;
   else if (coef<-1.0) coef=-1.0;

   aez=-coef*gravity;
   aez*=dmax(1.0-dabs(dez/maxspeed),0.0);

   dez+=aez/params->fps;
   dez*=pow(1.0/(1.0+damp),1.0/params->fps);

   if (elev<0.0) dez*=pow(1.0/(1.0+water),1.0/params->fps);

   cam->move_down(-dez/params->fps);

   dist=cam->get_dist();

   if (dist<hover)
      {
      dez=-dez;
      dez*=1.0/(1.0+bounce);

      cam->move_down(dist-hover);
      }

   // check for eye movement:

   if (dabs(speed)>VIEWER_MINDIFF ||
       dabs(turn)>VIEWER_MINDIFF ||
       dabs(incline)>VIEWER_MINDIFF ||
       dabs(dez)>VIEWER_MINDIFF) wakeup=TRUE;

   // change orientation of signposts:

   tparams->signpostturn=cam->get_angle();
   tparams->signpostincline=cam->get_pitch();

   if (eparams->usewaypoints) viewer->getearth()->getterrain()->propagate();

   // move eye point into projection center of panoramic waypoint:

   minipointdata *nearest=viewer->getearth()->getterrain()->getnearestpoint(cam->get_eye(),minipointopts::OPTION_TYPE_FREE);

   if (nearest!=NULL)
      if (nearest->opts!=NULL)
         if (nearest->opts->dataswitch==0)
            {
            miniv3d nearpoint(nearest->x,nearest->y,nearest->height+nearest->offset);
            minicoord nearcoord=viewer->map_l2g(minicoord(nearpoint));
            miniv3d nearvec=(nearcoord-cam->get_eye()).vec;

            double neardist=nearvec.normalize();
            double nearrad=3.0*viewer->len_l2g(nearest->size/2.0f);
            double nearspeed=0.1*neardist;

            if (neardist<nearrad)
               {
               cam->move(nearspeed*nearvec);
               if (nearspeed>VIEWER_MINDIFF) wakeup=TRUE;
               }
            }

   // update earth lighting
   if (eparams->usediffuse)
      {
      light=2*PI*VIEWER_ROTATION*viewer->time();
      lightdir=miniv3d(-cos(light),sin(light),0.0);
      eparams->lightdir=lightdir;
      viewer->propagate();
      wakeup=TRUE;
      }

   // render scene
   if (sw_stereo==0) viewer->render_geometry();
   else viewer->render_geometry(sbase,sw_anaglyph);

   // render the head-up display
   renderhud();

   // swap buffers and wait for next frame:

   glutSwapBuffers();

   // get time spent
   delta=viewer->gettimer();
   idle=1.0/params->fps-delta;

   // idle for the remainder of the frame
   viewer->idle(delta);

   // update quality parameters
   viewer->adapt(delta);

   // update statistics:

   accu_delta+=delta;
   if (idle>0.0) accu_idle+=idle;

   if (++avg_count>params->fps)
      {
      avg_delta=accu_delta/avg_count;
      avg_idle=accu_idle/avg_count;
      accu_delta=0.0;
      accu_idle=0.0f;
      avg_count=0;
      }
   }