Пример #1
0
        /// <summary>
        /// Pan the Camera around the Up vector by <c>theta_degrees</c> degrees.
        /// </summary>
        /// <param name="theta_degrees">
        /// A <see cref="System.Double"/>
        /// </param>
        public void RotatecAboutAxis(Vec3f axis, double theta_degrees)
        {
            double theta = theta_degrees * Math.PI / 180;
            Vec3f  tar   = Quatf.AxisAngleToQuatf(axis, (float)theta).Rotate(Forward.Val * dist) + Position.Val;

            Set(tar, qrot * Quatf.AxisAngleToQuatf(axis, (float)theta), dist);
        }
Пример #2
0
        public ViewerControl(ModelingHistory history) :
            base(new GraphicsMode(m_GLColorFormat, m_GLDepth, m_GLStencil, m_GLSamples, 48, 2, m_GLStereo), 3, 0, GraphicsContextFlags.Debug)
        {
            hist = history;

            //clusters = hist.Layers.GetClusters();
            clusters = hist.Layers.GetClusteringLayer(currentClusterLayer).clusters;

            this.SuspendLayout();
            this.BackColor = System.Drawing.Color.DimGray;
            this.ResumeLayout(false);

            base.CreateControl();

            this.Cursor = Cursors.Cross;
            VSync       = false;

            //setup viewables
            SetCluster();

            //setup camera
            m_Camera.Width  = Width;
            m_Camera.Height = Height;
            m_Camera.Set(new Vec3f(), Quatf.AxisAngleToQuatf(Vec3f.Z, -45), 10, false);

            //m_RefreshTimer.Elapsed += delegate { RefreshControl(); };
        }
Пример #3
0
        private void Synchronize(object obj, PropertyChangedEventArgs e)
        {
            if (SyncToCamera.Synchronizing)
            {
                return;
            }

            Synchronizing = true;
            Properties.DeferPropertyChanged = true;

            Position.Val  = SyncToCamera.Position.Val;
            Forward.Val   = SyncToCamera.Forward.Val;
            Up.Val        = SyncToCamera.Up.Val;
            NaturalUp.Val = SyncToCamera.NaturalUp.Val;
            Target.Val    = SyncToCamera.Target.Val;
            Ortho.Val     = SyncToCamera.Ortho.Val;
            Near.Val      = SyncToCamera.Near.Val;
            Far.Val       = SyncToCamera.Far.Val;
            Width.Val     = SyncToCamera.Width.Val;
            Height.Val    = SyncToCamera.Height.Val;
            FOV.Val       = SyncToCamera.FOV.Val;
            Scale.Val     = SyncToCamera.Scale.Val;
            qrot          = SyncToCamera.qrot;
            dist          = SyncToCamera.dist;

            Properties.DeferPropertyChanged = false;
            Synchronizing = false;
        }
Пример #4
0
 public void Set(Vec3f tar, Quatf rot, float dist, bool ortho)
 {
     Properties.DeferPropertyChanged = true;
     Set(tar, rot, dist);
     Ortho.Set(ortho);
     Properties.DeferPropertyChanged = false;
 }
Пример #5
0
        /// <summary>
        /// Orbit Camera Position around Target, maintaining distance to Target and the Up vector
        /// </summary>
        /// <param name="theta_degrees">
        /// A <see cref="System.Double"/>
        /// </param>
        public void OrbitTarget(double theta_degrees)
        {
            double theta  = theta_degrees * Math.PI / 180.0;
            Quatf  newrot = qrot * Quatf.AxisAngleToQuatf(NaturalUp.Val, (float)theta);

            Set(Target.Val, newrot, dist);
        }
Пример #6
0
        public static Vec3f Quat_RotPt(Vec3f pt, Vec3f rotaxis, float theta)
        {
            Quatf qrot  = new Quatf(FMath.Cos(theta * 0.5f), rotaxis * FMath.Sin(theta * 0.5f));
            Quatf qpt   = new Quatf(0.0f, pt);
            Quatf qconj = qrot.Conjugate();

            return(Quat_PointMult(qrot * qpt, qconj));
        }
Пример #7
0
 public static Vec3f Quat_PointMult(Quatf q1, Quatf q2)
 {
     return(new Vec3f()
     {
         x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,
         y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x,
         z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w
     });
 }
Пример #8
0
        public static CameraProperties SmoothBilateral(CameraProperties[] cams, int t0, float sigmatime, float sigmax)
        {
            int   l         = cams.Length;
            float wsumt     = 0;
            float wsumr     = 0;
            float wsumd     = 0;
            float sigtimesq = sigmatime * sigmatime;
            float sigxsq    = sigmax * sigmax;

            Vec3f tar0 = cams[t0].GetTarget();
            Quatf rot0 = cams[t0].qrot;
            float dis0 = cams[t0].dist;

            Vec3f t = new Vec3f();
            Quatf r = new Quatf(0, 0, 0, 0);
            float d = 0;

            // window to ~99%
            float siglg = Math.Max(sigmatime, sigmax);
            int   s     = Math.Max(0, (int)((float)t0 - siglg * 3.0f));
            int   e     = Math.Min(l - 1, (int)((float)t0 + siglg * 3.0f));

            for (int ti = s; ti <= e; ti++)
            {
                CameraProperties cam = cams[ti];

                float dtim = (ti - t0);
                float dtar = (cam.GetTarget() - tar0).Length;
                float drot = (cam.qrot - rot0).Length;
                float ddis = (cam.dist - dis0);

                float wg = (float)Math.Exp(-dtim * dtim / sigtimesq);
                float wt = wg * (float)Math.Exp(-dtar * dtar / sigxsq);
                float wr = wg * (float)Math.Exp(-drot * drot / sigxsq);
                float wd = wg * (float)Math.Exp(-ddis * ddis / sigxsq);

                wsumt += wt;
                wsumr += wr;
                wsumd += wd;

                t += cam.Target.Val * wt;
                r += cam.qrot * wr;
                d += cam.dist * wd;
            }

            t *= 1.0f / wsumt;
            r *= 1.0f / wsumr;
            d *= 1.0f / wsumd;

            return(new CameraProperties(t, r, d, cams[t0].Ortho.Val));
        }
Пример #9
0
        //private Matrix DoubleArrayToMatrix(double[] m)
        //{
        //    return new Matrix(new double[,] {
        //        { m[00], m[04], m[08], m[12] },
        //        { m[01], m[05], m[09], m[13] },
        //        { m[02], m[06], m[10], m[14] },
        //        { m[03], m[07], m[11], m[15] }
        //    });
        //}

        //public Matrix GetGLModelMatrix()
        //{
        //    double[] m = new double[16];
        //    GL.GetDouble(GetPName.ModelviewMatrix, m);
        //    return DoubleArrayToMatrix(m);
        //}

        //public Matrix GetGLProjectionMatrix()
        //{
        //    double[] m = new double[16];
        //    GL.GetDouble(GetPName.ProjectionMatrix, m);
        //    return DoubleArrayToMatrix(m);
        //}
        #endregion

        public void Set(Vec3f tar, Quatf rot, float dist)
        {
            rot       = rot.Normalize();
            this.qrot = rot;
            this.dist = dist;
            Vec3f _forward = rot.Rotate(Vec3f.Y);
            Vec3f _up      = rot.Rotate(Vec3f.Z);

            Position = tar - _forward * dist;
            Scale    = 50.0f / dist;
            Forward  = Vec3f.Normalize(_forward);
            Target   = tar;
            Up       = _up;
        }
Пример #10
0
        public static Quatf Slerp_NoInvert(Quatf q0, Quatf q1, float t)
        {
            float dot = q0 % q1;

            if (dot > -0.95f && dot < 0.95f)
            {
                float ang = FMath.Acos(dot);
                return((q0 * FMath.Sin(ang * (1.0f - t)) + q1 * FMath.Sin(ang * t)) / FMath.Sin(ang));
            }
            else
            {
                return(Lerp(q0, q1, t));
            }
        }
Пример #11
0
        public void OrbitTargetUpDown(double theta_degrees, bool clampflips = false)
        {
            double theta  = theta_degrees * Math.PI / 180.0;
            Quatf  newrot = qrot * Quatf.AxisAngleToQuatf(GetRight(), (float)theta);

            //if (clampflips)
            //{
            //    Vec3f newup = Vec3f.Normalize(newrot.Rotate(Vec3f.Y));
            //    float dot = FMath.PI / 2.0f - Vec3f.AngleBetween(newup, NaturalUp);
            //    if (dot < 0)
            //    {
            //        Vec3f newforward = Vec3f.Normalize(newrot.Rotate(-Vec3f.Z));
            //        Vec3f newright = newforward ^ newup;
            //        float sign = -Math.Sign(newforward % NaturalUp);
            //        newrot = newrot * Quatf.RotAxisAngleToQuatf(newright, dot * sign);
            //    }
            //}

            Set(Target, newrot, dist);
        }
Пример #12
0
        /*public void OrbitTargetUpDownNatural( double theta_degrees )
         *      {
         *              float fn = Forward.Val % NaturalUp.Val;
         *              if( ( theta_degrees < 0.0 && fn >= 0.95f ) || ( theta_degrees > 0.0 && fn <= -0.95f ) ) return;
         *
         *              double theta = theta_degrees * Math.PI / 180.0;
         *              Vec3f posreltar = Position.Val - Target.Val;
         *              Vec3f right = Forward.Val ^ NaturalUp.Val;
         *              float dist = (Target.Val - Position.Val).Length;
         *
         *              Properties.DeferPropertyChanged = true;
         *              bIgnoreChanges = true;
         *              Position.Set( Target.Val + Vec3f.Normalize( VecExtensions.RotateVectorAroundAxis( posreltar, right, (float) theta ) ) * dist );
         *              Up.Set( VecExtensions.RotateVectorAroundAxis( Up.Val, right, (float) theta ) );
         *              bIgnoreChanges = false;
         *              Target.Set( Target.Val );
         *              Properties.DeferPropertyChanged = false;
         *      }*/

        public void OrbitTargetUpDown(double theta_degrees, bool clampflips)
        {
            double theta  = theta_degrees * Math.PI / 180.0;
            Quatf  newrot = qrot * Quatf.AxisAngleToQuatf(GetRight(), (float)theta);

            if (clampflips)
            {
                // prevent camera from flipping over!
                Vec3f newup = Vec3f.Normalize(newrot.Rotate(Vec3f.Y));
                float dot   = FMath.PI / 2.0f - Vec3f.AngleBetween(newup, NaturalUp.Val);
                if (dot < 0)
                {
                    Vec3f newforward = Vec3f.Normalize(newrot.Rotate(-Vec3f.Z));
                    Vec3f newright   = newforward ^ newup;
                    float sign       = -Math.Sign(newforward % NaturalUp.Val);
                    newrot = newrot * Quatf.RotAxisAngleToQuatf(newright, dot * sign);
                }
            }

            Set(Target.Val, newrot, dist);
        }
Пример #13
0
        public static CameraProperties SmoothGaussian(CameraProperties[] cams, int t0, float sigma)
        {
            int   l    = cams.Length;
            float wsum = 0;
            float ss   = sigma * sigma;

            Vec3f t = new Vec3f();
            Quatf r = new Quatf(0, 0, 0, 0);
            float d = 0;

            t0 = Math.Max(0, Math.Min(cams.Length - 1, t0));

            // window to ~99%
            int s = Math.Max(0, (int)((float)t0 - sigma * 3.0f));
            int e = Math.Min(l - 1, (int)((float)t0 + sigma * 3.0f));

            for (int ti = s; ti <= e; ti++)
            {
                CameraProperties cam = cams[ti];

                float dtim = (ti - t0);
                float w    = (float)Math.Exp(-dtim * dtim / ss);
                wsum += w;

                t += cam.Target.Val * w;
                r += cam.qrot * w;
                d += cam.dist * w;
            }

            t *= 1.0f / wsum;
            r *= 1.0f / wsum;
            d *= 1.0f / wsum;

            if (t0 < 0 || t0 >= l)
            {
                System.Console.WriteLine("t0 = " + t0 + ", l = " + l);
            }

            return(new CameraProperties(t, r, d, cams[t0].Ortho.Val));
        }
Пример #14
0
        public void Set(Vec3f tar, Quatf rot, float dist)
        {
            rot = rot.Normalize();

            /*if( AlwaysUp )
             *          {
             *                  // prevent camera from rolling
             *                  Vec3f newright = Vec3f.Normalize( rot.Rotate( Vec3f.X ) );
             *                  Vec3f newup = Vec3f.Normalize( rot.Rotate( Vec3f.Y ) );
             *                  Vec3f newforward = Vec3f.Normalize( rot.Rotate( -Vec3f.Z ) );
             *
             *                  if( Math.Abs( newforward % NaturalUp ) < 0.95f ) {
             *                          Vec3f goodright = Vec3f.Normalize( newforward ^ Vec3f.Z );
             *                          float dot = Vec3f.AngleBetween( goodright, newright );
             *                          System.Console.WriteLine( newup.ToStringFormatted() + "  " + newright.ToStringFormatted() + "  " + goodright.ToStringFormatted() );
             *                          float sign = -Math.Sign( newright % NaturalUp );
             *                          //rot = rot * Quatf.RotAxisAngleToQuatf( newforward, dot * sign );
             *                  }
             *          }*/

            this.qrot = rot;
            this.dist = dist;

            Properties.DeferPropertyChanged = true;
            bIgnoreChanges = true;

            Vec3f fwd = rot.Rotate(-Vec3f.Z);
            Vec3f up  = rot.Rotate(Vec3f.Y);

            Position.Set(tar - fwd * dist);
            Scale.Set(50.0f / dist);
            Target.Set(tar);
            Forward.Set(Vec3f.Normalize(fwd));
            Up.Set(up);

            bIgnoreChanges = false;
            Properties.DeferPropertyChanged = false;
        }
Пример #15
0
        public static Quatf Slerp(Quatf q0, Quatf q1, float t)
        {
            Quatf q2;
            float dot = q0 % q1;

            if (dot < 0.00f)
            {
                dot = -dot; q2 = q1 * -1.0f;
            }
            else
            {
                q2 = q1;
            }

            if (dot < 0.95f)
            {
                float ang = FMath.Acos(dot);
                return((q0 * FMath.Sin(ang * (1.0f - t)) + q2 * FMath.Sin(ang * t)) / FMath.Sin(ang));
            }
            else
            {
                return(Lerp(q0, q2, t));
            }
        }
Пример #16
0
 public void Reset()
 {
     Set(new Vec3f(), Quatf.AxisAngleToQuatf(Vec3f.Z, -45) * Quatf.AxisAngleToQuatf(Vec3f.Y, -45), 10, false);
 }
Пример #17
0
        public CameraProperties[] GetCameras()
        {
            ModelingHistory history = ModelingHistory.history;

            CameraProperties artist   = null;
            CameraProperties bestview = null;

            Vec3f tar   = new Vec3f();
            Quatf rot   = new Quatf();
            float dist  = 0.0f;
            float ortho = 0.0f;

            List <Vec3f> selverts = new List <Vec3f>();
            Vec3f        anorm    = new Vec3f();

            foreach (int isnapshot in snapshots)
            {
                SnapshotScene    scene = history[isnapshot];
                CameraProperties cam   = scene.GetCamera();

                tar   += cam.GetTarget();
                rot   += cam.GetRotation();
                dist  += cam.GetDistance();
                ortho += (cam.GetOrtho() ? 1.0f : 0.0f);

                foreach (SnapshotModel model in scene.GetSelectedModels())
                {
                    Vec3f[] verts  = model.GetVerts();
                    Vec3f[] vnorms = model.GetVertNormals();
                    foreach (int ind in model.selinds)
                    {
                        selverts.Add(verts[ind]); anorm += vnorms[ind];
                    }
                }
            }

            int nsnapshots = snapshots.Count;

            if (nsnapshots == 0)
            {
                rot  = new Quatf(0.5f, -0.5f, -0.5f, -0.5f);
                dist = 10.0f;
                System.Console.WriteLine("Cluster with no snapshots " + start + ":" + end);
            }
            else
            {
                tar   /= (float)nsnapshots;
                rot   /= (float)nsnapshots;
                dist  /= (float)nsnapshots;
                ortho /= (float)nsnapshots;
            }

            artist = new CameraProperties(tar, rot, dist, (ortho >= 0.5f))
            {
                Name = "Artist"
            };

            bestview = artist;

            return(new CameraProperties[] { artist, bestview });
        }
Пример #18
0
 public CameraProperties(Vec3f tar, Quatf rot, float dist, bool ortho) : this()
 {
     Set(tar, rot, dist, ortho);
 }
Пример #19
0
 public Quatf(Quatf q)
 {
     x = q.x; y = q.y; z = q.z; w = q.w;
 }
Пример #20
0
 public static Quatf Lerp(Quatf q0, Quatf q1, float t)
 {
     return((q0 * (1.0f - t) + q1 * t).Normalize());
 }
Пример #21
0
        public SnapshotScene(string sPLYFilename, int timeindex, string command, string opts, SnapshotScene prev, bool nochange, bool cmdobjlist)
        {
            this.file      = MiscFileIO.GetFileNameOnly(sPLYFilename);
            this.timeindex = timeindex;
            this.command   = command;
            this.opts      = opts;
            this.prevscene = prev;

            cselected = 0;
            cedited   = 0;

            string[] objnames;
            bool[]   objvisibles;
            bool[]   objselecteds;
            bool[]   objactives;
            bool[]   objedits;
            string[] objplyfilenames;

            using (Stream s = new FileStream(sPLYFilename, FileMode.Open))
            {
                string plyline = FileIOFunctions.ReadTextString(s);
                if (plyline != "ply")
                {
                    throw new ArgumentException("SnapshotScene: Specified file is not .ply file");
                }

                ncameras = 0;
                nmodels  = 0;
                bool header = true;
                while (header)
                {
                    string cmd = FileIOFunctions.ReadTextString(s);
                    switch (cmd)
                    {
                    case "format":
                    case "property":
                        while (s.ReadByte() != 10)
                        {
                            ;                            // ignore the rest of the line
                        }
                        break;

                    case "comment":
                        string str = FileIOFunctions.ReadTextLine(s);
                        if (str.StartsWith("Created"))
                        {
                            switch (str.Split(new char[] { ' ' })[2])
                            {
                            case "Blender": ApplicationType = ApplicationTypes.BLENDER; break;
                            }
                        }
                        break;

                    case "element":
                        string variable = FileIOFunctions.ReadTextString(s);
                        int    val      = FileIOFunctions.ReadTextInteger(s);
                        switch (variable)
                        {
                        case "views": ncameras = val; break;

                        case "objects": nmodels = val; break;

                        default: throw new Exception("SnapshotScene: Unhandled element type " + variable);
                        }
                        break;

                    case "end_header": header = false; break;

                    default: throw new Exception("SnapshotScene: Unhandled command type " + cmd);
                    }
                }

                if (ApplicationType == ApplicationTypes.UNKNOWN)
                {
                    throw new Exception("SnapshotScene: PLY was created by an unknown application");
                }

                cameras = new CameraProperties[ncameras];
                for (int i = 0; i < ncameras; i++)
                {
                    // read viewing info
                    Vec3f  loc = new Vec3f(FileIOFunctions.ReadTextFloat(s), FileIOFunctions.ReadTextFloat(s), FileIOFunctions.ReadTextFloat(s));
                    float  w   = FileIOFunctions.ReadTextFloat(s);
                    float  x   = FileIOFunctions.ReadTextFloat(s);
                    float  y   = FileIOFunctions.ReadTextFloat(s);
                    float  z   = FileIOFunctions.ReadTextFloat(s);
                    Quatf  qua = (new Quatf(w, x, y, z)).Normalize();
                    float  dis = FileIOFunctions.ReadTextFloat(s);
                    String per = FileIOFunctions.ReadTextString(s);
                    cameras[i] = new CameraProperties(loc, qua, dis, (per == "ORTHO"));
                }

                int istart = 0, iend = 0, iinc = 0;
                switch (ApplicationType)
                {
                case ApplicationTypes.BLENDER:              // blender writes list of objects "backwards"; new objects are at beginning of list!
                    istart = nmodels - 1;
                    iend   = 0;
                    iinc   = -1;
                    break;

                default: throw new Exception("SnapshotScene: Unimplemented ApplicationType");
                }

                objnames        = new string[nmodels];
                objvisibles     = new bool[nmodels];
                objselecteds    = new bool[nmodels];
                objactives      = new bool[nmodels];
                objedits        = new bool[nmodels];
                objplyfilenames = new string[nmodels];

                for (int i = istart; i != iend + iinc; i += iinc)
                {
                    objnames[i]        = FileIOFunctions.ReadTextQuotedString(s);
                    objvisibles[i]     = (FileIOFunctions.ReadTextInteger(s) == 1);
                    objselecteds[i]    = (FileIOFunctions.ReadTextInteger(s) == 1);
                    objactives[i]      = (FileIOFunctions.ReadTextInteger(s) == 1);
                    objedits[i]        = (FileIOFunctions.ReadTextInteger(s) == 1);
                    objplyfilenames[i] = FileIOFunctions.ReadTextString(s);

                    if (objselecteds[i])
                    {
                        cselected++;
                    }
                    if (objedits[i])
                    {
                        cedited++;
                    }
                }
            }

            if (cedited > 1)
            {
                throw new Exception("more than one object being edited");
            }

            bool loadall = (prev == null || cmdobjlist);                // need to load every object?

            models       = new SnapshotModel[nmodels];
            modelscached = new SnapshotModel[nmodels];
            SnapshotModel[] pmodels = null;
            if (prev != null)
            {
                pmodels = prev.Models;
            }
            for (int i = 0; i < nmodels; i++)
            {
                bool prevsel = !cmdobjlist && (pmodels != null && pmodels[i] != null && pmodels[i].objselected);
                if (loadall || (objselecteds[i] && !nochange) || objselecteds[i] != prevsel || pmodels == null || pmodels[i] == null)
                {
                    models[i]             = new SnapshotModel(objplyfilenames[i]);
                    models[i].objind      = i;
                    models[i].objname     = objnames[i];
                    models[i].objvisible  = objvisibles[i];
                    models[i].objselected = objselecteds[i];
                    models[i].objactive   = objactives[i];
                    models[i].objedit     = objedits[i];
                    modelscached[i]       = models[i];
                }
                else
                {
                    models[i]       = null;
                    modelscached[i] = pmodels[i];
                }
            }
        }
Пример #22
0
 public void Set(Vec3f tar, Quatf rot, float dist, bool ortho)
 {
     Set(tar, rot, dist);
     Ortho = ortho;
 }
Пример #23
0
        public static CameraProperties SmoothBinary(CameraProperties[] cams, int t0, float epsilon, bool fromt0, float wtar, float wrot, float wdis)
        {
            int total = cams.Length;

            int   left     = t0 - 1;
            bool  lcdone   = (left < 0);
            Vec3f lctar    = cams[t0].GetTarget();
            Quatf lcrot    = cams[t0].GetRotation();
            float lcdis    = cams[t0].GetDistance();
            float leftdiff = -1;

            int   right     = t0 + 1;
            bool  rcdone    = (right > total - 1);
            Vec3f rctar     = cams[t0].GetTarget();
            Quatf rcrot     = cams[t0].GetRotation();
            float rcdis     = cams[t0].GetDistance();
            float rightdiff = -1;

            Vec3f avgtar   = cams[t0].GetTarget();
            Quatf avgrot   = cams[t0].GetRotation();
            float avgdis   = cams[t0].GetDistance();
            float maxdis   = cams[t0].GetDistance();
            float avgortho = (cams[t0].GetOrtho() ? 1.0f : 0.0f);
            int   count    = 1;

            while (!lcdone || !rcdone)
            {
                if (!lcdone)
                {
                    Vec3f ltar = cams[left].GetTarget();
                    Quatf lrot = cams[left].GetRotation();
                    float ldis = cams[left].GetDistance();

                    leftdiff = (ltar - lctar).Length * wtar + (lrot - lcrot).Length * wrot + Math.Abs(ldis - lcdis) * wdis;

                    if (leftdiff < epsilon)
                    {
                        avgtar   += ltar;
                        avgrot   += lrot;
                        avgdis   += ldis;
                        maxdis    = Math.Max(maxdis, ldis);
                        avgortho += (cams[left].GetOrtho() ? 1.0f : 0.0f);
                        count++;

                        if (!fromt0)
                        {
                            lctar = ltar; lcrot = lrot; lcdis = ldis;
                        }

                        left--;
                        lcdone = (left < 0);
                    }
                    else
                    {
                        lcdone = true;
                    }
                }

                if (!rcdone)
                {
                    Vec3f rtar = cams[right].GetTarget();
                    Quatf rrot = cams[right].GetRotation();
                    float rdis = cams[right].GetDistance();

                    rightdiff = (rtar - rctar).Length * wtar + (rrot - rcrot).Length * wrot + Math.Abs(rdis - rcdis) * wdis;

                    if (rightdiff < epsilon)
                    {
                        avgtar   += rtar;
                        avgrot   += rrot;
                        avgdis   += rdis;
                        maxdis    = Math.Max(maxdis, rdis);
                        avgortho += (cams[right].GetOrtho() ? 1.0f : 0.0f);
                        count++;

                        if (!fromt0)
                        {
                            rctar = rtar; rcrot = rrot; rcdis = rdis;
                        }

                        right++;
                        rcdone = (right > total - 1);
                    }
                    else
                    {
                        rcdone = true;
                    }
                }
            }

            avgtar   /= (float)count;
            avgrot   /= (float)count;
            avgdis   /= (float)count;
            avgortho /= (float)count;

            avgdis = maxdis;

            return(new CameraProperties(avgtar, avgrot, avgdis, (avgortho >= 0.5f)));
        }