예제 #1
0
        internal float SAHofPair(SSAABB boxa, SSAABB boxb)
        {
            SSAABB pairbox = boxa;

            pairbox.ExpandToFit(boxb);
            return(SAH(ref pairbox));
        }
예제 #2
0
        internal SSAABB AABBofPair(ssBVHNode <GO> nodea, ssBVHNode <GO> nodeb)
        {
            SSAABB box = nodea.box;

            box.ExpandToFit(nodeb.box);
            return(box);
        }
예제 #3
0
        public void addObject(GO newOb)
        {
            SSAABB box    = nAda.boundingBox(newOb);
            float  boxSAH = ssBVHNode <GO> .SA(ref box);

            rootBVH.addObject(nAda, newOb, ref box, boxSAH);
        }
예제 #4
0
        public void addObject(GO newOb)
        {
            SSAABB box    = SSAABB.FromSphere(nAda.objectpos(newOb), nAda.radius(newOb));
            float  boxSAH = ssBVHNode <GO> .SA(ref box);

            rootBVH.addObject(nAda, newOb, ref box, boxSAH);
        }
예제 #5
0
        internal float SAHofPair(ssBVHNode <GO> nodea, ssBVHNode <GO> nodeb)
        {
            SSAABB box = nodea.box;

            box.ExpandToFit(nodeb.box);
            return(SAH(ref box));
        }
예제 #6
0
        internal float SAH(ref SSAABB box)
        {
            float x_size = box.Max.X - box.Min.X;
            float y_size = box.Max.Y - box.Min.Y;
            float z_size = box.Max.Z - box.Min.Z;

            return(2.0f * ((x_size * y_size) + (x_size * z_size) + (y_size * z_size)));
        }
 internal void computeVolume(SSBVHNodeAdaptor <GO> nAda)
 {
     box = nAda.boundingBox(gobjects[0]);
     for (int i = 1; i < gobjects.Count; i++)
     {
         expandVolume(nAda, nAda.boundingBox(gobjects[i]));
     }
 }
예제 #8
0
        public SSSkeletalAnimation(int frameRate,
									SSSkeletalJoint[] jointInfo,
									SSSkeletalJointLocation[][] frames,
									SSAABB[] bounds = null)
        {
            _hierarchy = jointInfo;
            _frames = frames;
            _bounds = bounds;
            _frameRate = frameRate;
        }
예제 #9
0
        private SSSkeletalAnimationMD5 readAnimation()
        {
            Match[] matches;

            // header
            seekEntry ("MD5Version", "10");
            seekEntry ("commandline", SSMD5Parser._quotedStrRegex);

            matches = seekEntry ("numFrames", SSMD5Parser._uintRegex);
            var numFrames = Convert.ToInt32 (matches [1].Value);

            matches = seekEntry ("numJoints", SSMD5Parser._uintRegex);
            var numJoints = Convert.ToInt32 (matches [1].Value);

            matches = seekEntry ("frameRate", SSMD5Parser._uintRegex);
            var frameRate = Convert.ToInt32 (matches [1].Value);

            matches = seekEntry ("numAnimatedComponents", SSMD5Parser._uintRegex);
            int numAnimatedComponents = Convert.ToInt32 (matches [1].Value);
            var floatComponents = new float[numAnimatedComponents];

            // hierarchy
            seekEntry ("hierarchy", "{");
            var hierarchy = new SSSkeletalJoint[numJoints];
            var flags = new byte[numJoints];
            for (int j = 0; j < numJoints; ++j) {
                hierarchy [j] = readHierarchyEntry (out flags [j]);
            }
            seekEntry ("}");

            // bounds
            seekEntry ("bounds", "{");
            var bounds = new SSAABB[numFrames];
            for (int f = 0; f < numFrames; ++f) {
                bounds [f] = readBounds ();
            }
            seekEntry ("}");

            // base frame
            seekEntry ("baseframe", "{");
            for (int j = 0; j < numJoints; ++j) {
                hierarchy[j].bindPoseLocation = readBaseFrame ();
            }
            seekEntry ("}");

            // frames
            var frames = new SSSkeletalJointLocation[numFrames][];
            for (int f = 0; f < numFrames; ++f) {
                matches = seekEntry ("frame", SSMD5Parser._uintRegex, "{");
                int frameIdx = Convert.ToInt32 (matches [1].Value);
                frames [frameIdx] = readFrameJoints (flags, hierarchy, floatComponents);
                seekEntry ("}");
            }
            return new SSSkeletalAnimationMD5 (frameRate, hierarchy, frames, bounds);
        }
예제 #10
0
        internal SSAABB toAABB()
        {
            SSAABB aabb = new SSAABB();

            aabb.Min.X = box.Min.X;
            aabb.Min.Y = box.Min.Y;
            aabb.Min.Z = box.Min.Z;
            aabb.Max.X = box.Max.X;
            aabb.Max.Y = box.Max.Y;
            aabb.Max.Z = box.Max.Z;
            return(aabb);
        }
        private void expandVolume(SSBVHNodeAdaptor <GO> nAda, SSAABB targetBox)
        {
            var boxCopy = box;

            box.ExpandToFit(targetBox);

            var expanded = !boxCopy.Equals(box);

            if (expanded && parent != null)
            {
                parent.childExpanded(nAda, this);
            }
        }
예제 #12
0
        public void renderCells(ssBVHNode <SSObject> n, ref SSAABB parentbox, int depth)
        {
            float nudge = 0f;

            if (parentbox.Equals(n.box))
            {
                // attempt to nudge out of z-fighting
                nudge = 0.2f;
            }

            if (highlightNodes.Contains(n))
            {
                if (n.gobjects == null)
                {
                    GL.Color4(Color.FromArgb(255, 25, 25, 100));
                }
                else
                {
                    GL.Color4(Color.Green);
                }
            }
            else
            {
                if (n.gobjects == null)
                {
                    GL.Color4(Color.FromArgb(255, 20, 20, 20));
                }
                else
                {
                    GL.Color4(Color.DarkRed);
                }
            }

            Vector3 nudgeVect = new Vector3(nudge);
            Vector3 scale     = n.box.max - n.box.min - 2f * nudgeVect;
            Matrix4 mat       = Matrix4.CreateScale(scale) * Matrix4.CreateTranslation(n.box.min + nudgeVect);

            GL.PushMatrix();
            GL.MultMatrix(ref mat);
            ibo.DrawElements(PrimitiveType.Lines, false);
            GL.PopMatrix();

            if (n.right != null)
            {
                renderCells(n.right, ref n.box, depth: depth + 1);
            }
            if (n.left != null)
            {
                renderCells(n.left, ref n.box, depth: depth + 1);
            }
        }
예제 #13
0
 internal void findOverlappingLeaves(SSBVHNodeAdaptor <GO> nAda, SSAABB aabb, List <ssBVHNode <GO> > overlapList)
 {
     if (toAABB().IntersectsAABB(aabb))
     {
         if (gobjects != null)
         {
             overlapList.Add(this);
         }
         else
         {
             left.findOverlappingLeaves(nAda, aabb, overlapList);
             right.findOverlappingLeaves(nAda, aabb, overlapList);
         }
     }
 }
        internal static void childRefit(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> curNode, bool propagate = true)
        {
            do
            {
                SSAABB         oldbox = curNode.box;
                ssBVHNode <GO> left   = curNode.left;
                ssBVHNode <GO> right  = curNode.right;

                // start with the left box
                SSAABB newBox = left.box;

                // expand any dimension bigger in the right node
                if (right.box.Min.X < newBox.Min.X)
                {
                    newBox.Min.X = right.box.Min.X;
                }
                if (right.box.Min.Y < newBox.Min.Y)
                {
                    newBox.Min.Y = right.box.Min.Y;
                }
                if (right.box.Min.Z < newBox.Min.Z)
                {
                    newBox.Min.Z = right.box.Min.Z;
                }

                if (right.box.Max.X > newBox.Max.X)
                {
                    newBox.Max.X = right.box.Max.X;
                }
                if (right.box.Max.Y > newBox.Max.Y)
                {
                    newBox.Max.Y = right.box.Max.Y;
                }
                if (right.box.Max.Z > newBox.Max.Z)
                {
                    newBox.Max.Z = right.box.Max.Z;
                }

                // now set our box to the newly created box
                curNode.box = newBox;

                // and walk up the tree
                curNode = curNode.parent;
            } while (propagate && curNode != null);
        }
예제 #15
0
            /// <summary>
            /// Computes vertex positions and normals (based on the state of runtime joint hierarchy).
            /// Updates VBO with the result.
            /// </summary>
            /// <returns>AABB of the vertices.</returns>
            public SSAABB ComputeVertices()
            {
                SSAABB aabb = new SSAABB(float.PositiveInfinity, float.NegativeInfinity);

                for (int v = 0; v < _runtimeMesh.numVertices; ++v)
                {
                    // position
                    Vector3 pos = _runtimeMesh.computeVertexPos(v);
                    _vertices [v].Position = pos;
                    aabb.UpdateMin(pos);
                    aabb.UpdateMax(pos);
                    // normal
                    _vertices [v].Normal = _runtimeMesh.computeVertexNormal(v);
                }
                _vbo.UpdateBufferData(_vertices);
                _bvh = null; // invalidate bvh
                return(aabb);
            }
예제 #16
0
        internal void removeLeaf(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> removeLeaf)
        {
            if (left == null || right == null)
            {
                throw new Exception("bad intermediate node");
            }
            ssBVHNode <GO> keepLeaf;

            if (removeLeaf == left)
            {
                keepLeaf = right;
            }
            else if (removeLeaf == right)
            {
                keepLeaf = left;
            }
            else
            {
                throw new Exception("removeLeaf doesn't match any leaf!");
            }

            // "become" the leaf we are keeping.
            box  = keepLeaf.box;
            left = keepLeaf.left; right = keepLeaf.right; gobjects = keepLeaf.gobjects;
            // clear the leaf..
            // keepLeaf.left = null; keepLeaf.right = null; keepLeaf.gobjects = null; keepLeaf.parent = null;

            if (gobjects == null)
            {
                left.parent = this; right.parent = this; // reassign child parents..
                this.setDepth(this.depth);               // this reassigns depth for our children
            }
            else
            {
                // map the objects we adopted to us...
                gobjects.ForEach(o => { nAda.mapObjectToBVHLeaf(o, this); });
            }

            // propagate our new volume..
            if (parent != null)
            {
                parent.childRefit(nAda);
            }
        }
예제 #17
0
파일: PickHelp.cs 프로젝트: Hengle/Fusion3D
        // Ray to AABB (AxisAlignedBoundingBox)
        // http://gamedev.stackexchange.com/questions/18436/most-efficient-aabb-vs-ray-collision-algorithms

        public static bool intersectRayAABox2(SSRay ray, SSAABB box, ref float tnear, ref float tfar)
        {
            Vector3d T_1    = new Vector3d();
            Vector3d T_2    = new Vector3d();  // vectors to hold the T-values for every direction
            double   t_near = double.MinValue; // maximums defined in float.h
            double   t_far  = double.MaxValue;

            for (int i = 0; i < 3; i++)
            {     //we test slabs in every direction
                if (ray.dir[i] == 0)
                { // ray parallel to planes in this direction
                    if ((ray.pos[i] < box.Min[i]) || (ray.pos[i] > box.Max[i]))
                    {
                        return(false); // parallel AND outside box : no intersection possible
                    }
                }
                else
                { // ray not parallel to planes in this direction
                    T_1[i] = (box.Min[i] - ray.pos[i]) / ray.dir[i];
                    T_2[i] = (box.Max[i] - ray.pos[i]) / ray.dir[i];

                    if (T_1[i] > T_2[i])
                    {                  // we want T_1 to hold values for intersection with near plane
                        var swp = T_2; // swap
                        T_1 = swp; T_2 = T_1;
                    }
                    if (T_1[i] > t_near)
                    {
                        t_near = T_1[i];
                    }
                    if (T_2[i] < t_far)
                    {
                        t_far = T_2[i];
                    }
                    if ((t_near > t_far) || (t_far < 0))
                    {
                        return(false);
                    }
                }
            }
            tnear = (float)t_near; tfar = (float)t_far; // put return values in place
            return(true);                               // if we made it here, there was an intersection - YAY
        }
예제 #18
0
        public override void renderMesh(SSRenderConfig renderConfig)
        {
            // apply animation channels
            _hierarchy.applySkeletalControllers(_channelControllers);

            SSAABB totalAABB = new SSAABB(float.PositiveInfinity, float.NegativeInfinity);

            foreach (var sub in _renderSubMeshes)
            {
                SSAABB aabb = sub.ComputeVertices();
                sub.renderMesh(renderConfig);
                totalAABB.ExpandBy(aabb);
            }
            // update the bounding sphere
            var sphere = totalAABB.ToSphere();

            base.boundingSphereCenter = sphere.center;
            base.boundingSphereRadius = sphere.radius;
            NotifyMeshPositionOrSizeChanged();
        }
예제 #19
0
        internal void childRefit(SSBVHNodeAdaptor <GO> nAda, bool recurse = true)
        {
            SSAABB oldbox = box;

            box.Min.X = left.box.Min.X; box.Max.X = left.box.Max.X;
            box.Min.Y = left.box.Min.Y; box.Max.Y = left.box.Max.Y;
            box.Min.Z = left.box.Min.Z; box.Max.Z = left.box.Max.Z;

            if (right.box.Min.X < box.Min.X)
            {
                box.Min.X = right.box.Min.X;
            }
            if (right.box.Min.Y < box.Min.Y)
            {
                box.Min.Y = right.box.Min.Y;
            }
            if (right.box.Min.Z < box.Min.Z)
            {
                box.Min.Z = right.box.Min.Z;
            }

            if (right.box.Max.X > box.Max.X)
            {
                box.Max.X = right.box.Max.X;
            }
            if (right.box.Max.Y > box.Max.Y)
            {
                box.Max.Y = right.box.Max.Y;
            }
            if (right.box.Max.Z > box.Max.Z)
            {
                box.Max.Z = right.box.Max.Z;
            }

            if (recurse && parent != null)
            {
                parent.childRefit(nAda);
            }
        }
예제 #20
0
        public static bool intersectRayAABox1(SSRay ray, SSAABB box, ref float tnear, ref float tfar)
        {
            // r.dir is unit direction vector of ray
            Vector3 dirfrac = new Vector3();
            float   t;

            dirfrac.X = 1.0f / ray.dir.X;
            dirfrac.Y = 1.0f / ray.dir.Y;
            dirfrac.Z = 1.0f / ray.dir.Z;
            // lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
            // r.org is origin of ray
            float t1 = (box.Min.X - ray.pos.X) * dirfrac.X;
            float t2 = (box.Max.X - ray.pos.X) * dirfrac.X;
            float t3 = (box.Min.Y - ray.pos.Y) * dirfrac.Y;
            float t4 = (box.Max.Y - ray.pos.Y) * dirfrac.Y;
            float t5 = (box.Min.Z - ray.pos.Z) * dirfrac.Z;
            float t6 = (box.Max.Z - ray.pos.Z) * dirfrac.Z;

            float tmin = Math.Max(Math.Max(Math.Min(t1, t2), Math.Min(t3, t4)), Math.Min(t5, t6));
            float tmax = Math.Min(Math.Min(Math.Max(t1, t2), Math.Max(t3, t4)), Math.Max(t5, t6));

            // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us
            if (tmax < 0)
            {
                t = tmax;
                return(false);
            }

            // if tmin > tmax, ray doesn't intersect AABB
            if (tmin > tmax)
            {
                t = tmax;
                return(false);
            }

            t = tmin;
            return(true);
        }
예제 #21
0
        public static SSAABB GetBoundingBox(this LoadResult obj)
        {
            var bbox = new SSAABB();

            foreach (var g in obj.Groups)
            {
                foreach (var f in g.Faces)
                {
                    if (f.Count != 3)
                    {
                        throw new NotImplementedException("Non triangular face found in obj");
                    }

                    var v0 = obj.Vertices[f[0].VertexIndex - 1].ToVector3();
                    var v1 = obj.Vertices[f[1].VertexIndex - 1].ToVector3();
                    var v2 = obj.Vertices[f[2].VertexIndex - 1].ToVector3();

                    var t = new Triangle(v0, v1, v2, null);
                    bbox.ExpandToFit(t.BoundingBox);
                }
            }
            return(bbox);
        }
예제 #22
0
        internal bool refitVolume(SSBVHNodeAdaptor <GO> nAda)
        {
            if (gobjects.Count == 0)
            {
                throw new NotImplementedException();
            }                                                                  // TODO: fix this... we should never get called in this case...

            SSAABB oldbox = box;

            computeVolume(nAda);
            if (!box.Equals(oldbox))
            {
                if (parent != null)
                {
                    parent.childRefit(nAda);
                }
                return(true);
            }
            else
            {
                return(false);
            }
        }
예제 #23
0
        public static bool intersectRayAABox1(raytracinginoneweekend.Ray ray, SSAABB box, ref float tnear, ref float tfar)
        {
            float tMin = tnear;
            float tMax = tfar;

            if (!intersectPlane(box.Min.X, box.Max.X, ray.Direction.X, ray.Origin.X, ref tMin, ref tMax))
            {
                return(false);
            }
            if (!intersectPlane(box.Min.Y, box.Max.Y, ray.Direction.Y, ray.Origin.Y, ref tMin, ref tMax))
            {
                return(false);
            }
            if (!intersectPlane(box.Min.Z, box.Max.Z, ray.Direction.Z, ray.Origin.Z, ref tMin, ref tMax))
            {
                return(false);
            }
            if (tMax > tfar)
            {
                throw new Exception("tMax > tfar");
            }

            return(true);
        }
예제 #24
0
        // Ray to AABB (AxisAlignedBoundingBox)
        // http://gamedev.stackexchange.com/questions/18436/most-efficient-aabb-vs-ray-collision-algorithms
        public static bool intersectRayAABox2(SSRay ray, SSAABB box, ref float tnear, ref float tfar)
        {
            Vector3d T_1 = new Vector3d();
            Vector3d T_2 = new Vector3d(); // vectors to hold the T-values for every direction
            double t_near = double.MinValue; // maximums defined in float.h
            double t_far = double.MaxValue;

            for (int i = 0; i < 3; i++){ //we test slabs in every direction
                if (ray.dir[i] == 0){ // ray parallel to planes in this direction
                    if ((ray.pos[i] < box.Min[i]) || (ray.pos[i] > box.Max[i])) {
                        return false; // parallel AND outside box : no intersection possible
                    }
                } else { // ray not parallel to planes in this direction
                    T_1[i] = (box.Min[i] - ray.pos[i]) / ray.dir[i];
                    T_2[i] = (box.Max[i] - ray.pos[i]) / ray.dir[i];

                    if(T_1[i] > T_2[i]){ // we want T_1 to hold values for intersection with near plane
                        var swp = T_2; // swap
                        T_1 = swp; T_2 = T_1;
                    }
                    if (T_1[i] > t_near){
                        t_near = T_1[i];
                    }
                    if (T_2[i] < t_far){
                        t_far = T_2[i];
                    }
                    if( (t_near > t_far) || (t_far < 0) ){
                        return false;
                    }
                }
            }
            tnear = (float)t_near; tfar = (float)t_far; // put return values in place
            return true; // if we made it here, there was an intersection - YAY
        }
예제 #25
0
        public SSSkeletalAnimationMD5(int frameRate,
									   SSSkeletalJoint[] jointInfo,
									   SSSkeletalJointLocation[][] frames,
									   SSAABB[] bounds)
            : base(frameRate, jointInfo, frames, bounds)
        {
        }
예제 #26
0
 public List <ssBVHNode <GO> > traverse(SSAABB volume)
 {
     return(traverse(box => box.IntersectsAABB(volume)));
 }
예제 #27
0
        public static bool intersectRayAABox1(SSRay ray, SSAABB box, ref float tnear, ref float tfar)
        {
            // r.dir is unit direction vector of ray
            Vector3 dirfrac = new Vector3();
            float t;
            dirfrac.X = 1.0f / ray.dir.X;
            dirfrac.Y = 1.0f / ray.dir.Y;
            dirfrac.Z = 1.0f / ray.dir.Z;
            // lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
            // r.org is origin of ray
            float t1 = (box.Min.X - ray.pos.X)*dirfrac.X;
            float t2 = (box.Max.X - ray.pos.X)*dirfrac.X;
            float t3 = (box.Min.Y - ray.pos.Y)*dirfrac.Y;
            float t4 = (box.Max.Y - ray.pos.Y)*dirfrac.Y;
            float t5 = (box.Min.Z - ray.pos.Z)*dirfrac.Z;
            float t6 = (box.Max.Z - ray.pos.Z)*dirfrac.Z;

            float tmin = Math.Max(Math.Max(Math.Min(t1, t2), Math.Min(t3, t4)), Math.Min(t5, t6));
            float tmax = Math.Min(Math.Min(Math.Max(t1, t2), Math.Max(t3, t4)), Math.Max(t5, t6));

            // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us
            if (tmax < 0)
            {
                t = tmax;
                return false;
            }

            // if tmin > tmax, ray doesn't intersect AABB
            if (tmin > tmax)
            {
                t = tmax;
                return false;
            }

            t = tmin;
            return true;
        }
        internal static void addObject(SSBVHNodeAdaptor <GO> nAda, ssBVHNode <GO> curNode, GO newOb, ref SSAABB newObBox, float newObSAH)
        {
            // 1. first we traverse the node looking for the best leaf
            while (curNode.gobjects == null)
            {
                // find the best way to add this object.. 3 options..
                // 1. send to left node  (L+N,R)
                // 2. send to right node (L,R+N)
                // 3. merge and pushdown left-and-right node (L+R,N)

                var left  = curNode.left;
                var right = curNode.right;

                float leftSAH               = SA(left);
                float rightSAH              = SA(right);
                float sendLeftSAH           = rightSAH + SA(left.box.ExpandedBy(newObBox)); // (L+N,R)
                float sendRightSAH          = leftSAH + SA(right.box.ExpandedBy(newObBox)); // (L,R+N)
                float mergedLeftAndRightSAH = SA(AABBofPair(left, right)) + newObSAH;       // (L+R,N)

                // Doing a merge-and-pushdown can be expensive, so we only do it if it's notably better
                const float MERGE_DISCOUNT = 0.3f;

                if (mergedLeftAndRightSAH < (Math.Min(sendLeftSAH, sendRightSAH)) * MERGE_DISCOUNT)
                {
                    addObject_Pushdown(nAda, curNode, newOb);
                    return;
                }
                else
                {
                    if (sendLeftSAH < sendRightSAH)
                    {
                        curNode = left;
                    }
                    else
                    {
                        curNode = right;
                    }
                }
            }

            // 2. then we add the object and map it to our leaf
            curNode.gobjects.Add(newOb);
            nAda.mapObjectToBVHLeaf(newOb, curNode);
            curNode.refitVolume(nAda);
            // split if necessary...
            curNode.splitIfNecessary(nAda);
        }
 internal void addObject(SSBVHNodeAdaptor <GO> nAda, GO newOb, ref SSAABB newObBox, float newObSAH)
 {
     addObject(nAda, this, newOb, ref newObBox, newObSAH);
 }
예제 #30
0
        private SSSkeletalAnimationMD5 readAnimation()
        {
            Match[] matches;

            // header
            seekEntry("MD5Version", "10");
            seekEntry("commandline", SSMD5Parser._quotedStrRegex);

            matches = seekEntry("numFrames", SSMD5Parser._uintRegex);
            var numFrames = Convert.ToInt32(matches [1].Value);

            matches = seekEntry("numJoints", SSMD5Parser._uintRegex);
            var numJoints = Convert.ToInt32(matches [1].Value);

            matches = seekEntry("frameRate", SSMD5Parser._uintRegex);
            var frameRate = Convert.ToInt32(matches [1].Value);

            matches = seekEntry("numAnimatedComponents", SSMD5Parser._uintRegex);
            int numAnimatedComponents = Convert.ToInt32(matches [1].Value);
            var floatComponents       = new float[numAnimatedComponents];

            // hierarchy
            seekEntry("hierarchy", "{");
            var hierarchy = new SSSkeletalJoint[numJoints];
            var flags     = new byte[numJoints];

            for (int j = 0; j < numJoints; ++j)
            {
                hierarchy [j] = readHierarchyEntry(out flags [j]);
            }
            seekEntry("}");

            // bounds
            seekEntry("bounds", "{");
            var bounds = new SSAABB[numFrames];

            for (int f = 0; f < numFrames; ++f)
            {
                bounds [f] = readBounds();
            }
            seekEntry("}");

            // base frame
            seekEntry("baseframe", "{");
            for (int j = 0; j < numJoints; ++j)
            {
                hierarchy[j].bindPoseLocation = readBaseFrame();
            }
            seekEntry("}");

            // frames
            var frames = new SSSkeletalJointLocation[numFrames][];

            for (int f = 0; f < numFrames; ++f)
            {
                matches = seekEntry("frame", SSMD5Parser._uintRegex, "{");
                int frameIdx = Convert.ToInt32(matches [1].Value);
                frames [frameIdx] = readFrameJoints(flags, hierarchy, floatComponents);
                seekEntry("}");
            }
            return(new SSSkeletalAnimationMD5(frameRate, hierarchy, frames, bounds));
        }
예제 #31
0
        private void ComputeProjections(List<SSObject> objects,
                                        SSLightBase light,
                                        Matrix4 cameraView, Matrix4 cameraProj)
        {
            if (light.GetType() != typeof(SSDirectionalLight)) {
                throw new NotSupportedException();
            }
            SSDirectionalLight dirLight = (SSDirectionalLight)light;

            // light-aligned unit vectors
            Vector3 lightZ = dirLight.Direction.Normalized();
            Vector3 lightX, lightY;
            OpenTKHelper.TwoPerpAxes(lightZ, out lightX, out lightY);
            // transform matrix from regular space into light aligned space
            Matrix4 lightTransform = new Matrix4 (
                lightX.X, lightX.Y, lightX.Z, 0f,
                lightY.X, lightY.Y, lightY.Z, 0f,
                lightZ.X, lightZ.Y, lightZ.Z, 0f,
                0f,       0f,       0f,       0f
            );

            // Find AABB of frustum corners in light coordinates
            Matrix4 cameraViewProj = cameraView * cameraProj;
            SSAABB frustumLightBB = SSAABB.FromFrustum(ref lightTransform, ref cameraViewProj);

            bool shrink = false;
            SSAABB objsLightBB = new SSAABB (float.PositiveInfinity, float.NegativeInfinity);
            #if true
            // (optional) scene dependent optimization
            // Trim the light-bounding box by the shadow receivers (only in light-space x,y,maxz)
            FrustumCuller cameraFrustum = new FrustumCuller (ref cameraViewProj);

            foreach (var obj in objects) {
                // pass through all shadow casters and receivers
                if (obj.renderState.toBeDeleted || obj.localBoundingSphereRadius <= 0f
                 || !obj.renderState.visible || !obj.renderState.receivesShadows) {
                    continue;
                } else if (cameraFrustum.isSphereInsideFrustum(obj.worldBoundingSphere)) {
                    // determine AABB in light coordinates of the objects so far
                    shrink = true;
                    Vector3 lightAlignedPos = Vector3.Transform(obj.worldBoundingSphereCenter, lightTransform);
                    Vector3 rad = new Vector3(obj.worldBoundingSphereRadius);
                    Vector3 localMin = lightAlignedPos - rad;
                    Vector3 localMax = lightAlignedPos + rad;
                    objsLightBB.UpdateMin(localMin);
                    objsLightBB.UpdateMax(localMax);
                }
            }
            #endif

            // Optimize the light-frustum-projection bounding box by the object-bounding-box
            SSAABB resultLightBB = new SSAABB(float.PositiveInfinity, float.NegativeInfinity);
            if (shrink) {
                // shrink the XY & far-Z coordinates..
                resultLightBB.Min.Xy = Vector2.ComponentMax(frustumLightBB.Min.Xy, objsLightBB.Min.Xy);
                resultLightBB.Min.Z = objsLightBB.Min.Z;
                resultLightBB.Max = Vector3.ComponentMin(frustumLightBB.Max, objsLightBB.Max);
            } else {
                resultLightBB = frustumLightBB;
            }

            // View and projection matrices, used by the scene later
            viewProjFromLightAlignedBB(ref resultLightBB, ref lightTransform, ref lightY,
                                       out m_shadowViewMatrix, out m_shadowProjMatrix);

            // Now extend Z of the result AABB to cover shadow-casters closer to the light inside the
            // original box
            foreach (var obj in objects) {
                if (obj.renderState.toBeDeleted || obj.localBoundingSphereRadius <= 0f
                 || !obj.renderState.visible || !obj.renderState.castsShadow) {
                    continue;
                }
                Vector3 lightAlignedPos = Vector3.Transform(obj.worldBoundingSphereCenter, lightTransform);
                Vector3 rad = new Vector3(obj.worldBoundingSphereRadius);
                Vector3 localMin = lightAlignedPos - rad;
                if (localMin.Z < resultLightBB.Min.Z) {
                    Vector3 localMax = lightAlignedPos + rad;
                    if (OpenTKHelper.RectsOverlap(resultLightBB.Min.Xy,
                                                  resultLightBB.Max.Xy,
                                                  localMin.Xy,
                                                  localMax.Xy)) {
                        resultLightBB.Min.Z = localMin.Z;
                    }
                }
            }

            // Generate frustum culler from the BB extended towards light to include shadow casters
            Matrix4 frustumView, frustumProj;
            viewProjFromLightAlignedBB(ref resultLightBB, ref lightTransform, ref lightY,
                                       out frustumView, out frustumProj);
            Matrix4 frustumMatrix = frustumView * frustumProj;
            FrustumCuller = new FrustumCuller (ref frustumMatrix);
        }
예제 #32
0
        protected static void viewProjFromLightAlignedBB(ref SSAABB bb, 
                                                         ref Matrix4 lightTransform, 
                                                         ref Vector3 lightY,
                                                         out Matrix4 viewMatrix,
                                                         out Matrix4 projMatrix)
        {
            // Use center of AABB in regular coordinates to get the view matrix
            Vector3 targetLightSpace = bb.Center();
            Vector3 eyeLightSpace = new Vector3 (targetLightSpace.X,
                targetLightSpace.Y,
                bb.Min.Z);
            Vector3 viewTarget = Vector3.Transform(targetLightSpace, lightTransform.Inverted());
            Vector3 viewEye = Vector3.Transform(eyeLightSpace, lightTransform.Inverted());
            Vector3 viewUp = lightY;
            viewMatrix = Matrix4.LookAt(viewEye, viewTarget, viewUp);

            // Finish the projection matrix
            Vector3 diff = bb.Diff();
            float width, height, nearZ, farZ;
            width = diff.X;
            height = diff.Y;
            nearZ = 1f;
            farZ = 1f + diff.Z;
            projMatrix = Matrix4.CreateOrthographic(width, height, nearZ, farZ);
        }
예제 #33
0
        protected void ComputeProjections(
            List<SSObject> objects,
            Matrix4 cameraView,
            Matrix4 cameraProj,
            float fov, float aspect, float cameraNearZ, float cameraFarZ)
        {
            if (m_light.GetType() != typeof(SSDirectionalLight)) {
                throw new NotSupportedException();
            }
            SSDirectionalLight dirLight = (SSDirectionalLight)m_light;

            // light-aligned unit vectors
            Vector3 lightZ = dirLight.Direction.Normalized();
            Vector3 lightX, lightY;
            OpenTKHelper.TwoPerpAxes(lightZ, out lightX, out lightY);
            // transform matrix from regular space into light aligned space
            Matrix4 lightTransform = new Matrix4 (
                lightX.X, lightX.Y, lightX.Z, 0f,
                lightY.X, lightY.Y, lightY.Z, 0f,
                lightZ.X, lightZ.Y, lightZ.Z, 0f,
                0f,       0f,       0f,       0f
            );

            // Step 0: camera projection matrix (nearZ and farZ modified) for each frustum split
            float prevFarZ = cameraNearZ;
            for (int i = 0; i < c_numberOfSplits; ++i) {
                // generate frustum splits using Practical Split Scheme (GPU Gems 3, 10.2.1)
                float iRatio = (float)(i+1) / (float)c_numberOfSplits;
                float cLog = cameraNearZ * (float)Math.Pow(cameraFarZ / cameraNearZ, iRatio);
                float cUni = cameraNearZ + (cameraFarZ - cameraNearZ) * iRatio;
                float nextFarZ = LogVsLinearSplitFactor * cLog + (1f - LogVsLinearSplitFactor) * cUni;
                float nextNearZ = prevFarZ;

                // exported to the shader
                m_viewSplits [i] = nextFarZ;

                // create a view proj matrix with the nearZ, farZ values for the current split
                m_frustumViewProjMatrices[i] = cameraView
                                             * Matrix4.CreatePerspectiveFieldOfView(fov, aspect, nextNearZ, nextFarZ);

                // create light-aligned AABBs of frustums
                m_frustumLightBB [i] = SSAABB.FromFrustum(ref lightTransform, ref m_frustumViewProjMatrices [i]);

                prevFarZ = nextFarZ;
            }

            #if true
            // Optional scene-dependent optimization
            for (int i = 0; i < c_numberOfSplits; ++i) {
                m_objsLightBB[i] = new SSAABB(float.PositiveInfinity, float.NegativeInfinity);
                m_splitFrustums[i] = new SSFrustumCuller(ref m_frustumViewProjMatrices[i]);
                m_shrink[i] = false;
            }
            foreach (var obj in objects) {
                // pass through all shadow casters and receivers
                if (obj.renderState.toBeDeleted  || obj.localBoundingSphereRadius <= 0f
                 || !obj.renderState.visible || !obj.renderState.receivesShadows) {
                    continue;
                } else {
                    for (int i = 0; i < c_numberOfSplits; ++i) {
                        if (m_splitFrustums[i].isSphereInsideFrustum(obj.worldBoundingSphere)) {
                            // determine AABB in light coordinates of the objects so far
                            m_shrink[i] = true;
                            Vector3 lightAlignedPos = Vector3.Transform(obj.worldBoundingSphereCenter, lightTransform);
                            Vector3 rad = new Vector3(obj.worldBoundingSphereRadius);
                            Vector3 localMin = lightAlignedPos - rad;
                            Vector3 localMax = lightAlignedPos + rad;

                            m_objsLightBB[i].UpdateMin(localMin);
                            m_objsLightBB[i].UpdateMax(localMax);
                        }
                    }
                }
            }
            #endif

            for (int i = 0; i < c_numberOfSplits; ++i) {
                if (m_shrink [i]) {
                    m_resultLightBB[i].Min = Vector3.ComponentMax(m_frustumLightBB [i].Min,
                                                                  m_objsLightBB [i].Min);
                    m_resultLightBB [i].Max = Vector3.ComponentMin(m_frustumLightBB [i].Max,
                                                                     m_objsLightBB [i].Max);
                } else {
                    m_resultLightBB [i] = m_frustumLightBB [i];
                }
            }

            for (int i = 0; i < c_numberOfSplits; ++i) {
                // Obtain view + projection + crop matrix, need it later
                Matrix4 shadowView, shadowProj;
                viewProjFromLightAlignedBB(ref m_resultLightBB [i], ref lightTransform, ref lightY,
                                           out shadowView, out shadowProj);
                m_shadowViewProjMatrices[i] = shadowView * shadowProj * c_cropMatrices[i];
                // obtain view + projection + clio + bias
                m_shadowViewProjBiasMatrices[i] = m_shadowViewProjMatrices[i] * c_biasMatrix;

                // There is, currently, no mathematically derived solution to how much Poisson spread scaling
                // you need for each split. Current improvisation combines 1) increasing spread for the near
                // splits; reducing spread for the far splits and 2) reducing spread for splits with larger
                // light-aligned areas; increasing spread for splits with smaller light-aligned areas
                m_poissonScaling [i] = m_resultLightBB [i].Diff().Xy / (100f * (float)Math.Pow(3.0, i - 1));
            }

            // Combine all splits' BB into one and extend it to include shadow casters closer to light
            SSAABB castersLightBB = new SSAABB (float.PositiveInfinity, float.NegativeInfinity);
            for (int i = 0; i < c_numberOfSplits; ++i) {
                castersLightBB.Combine(ref m_resultLightBB [i]);
            }

            // extend Z of the AABB to cover shadow-casters closer to the light
            foreach (var obj in objects) {
                if (obj.renderState.toBeDeleted || obj.localBoundingSphereRadius <= 0f
                 || !obj.renderState.visible || !obj.renderState.castsShadow) {
                    continue;
                } else {
                    Vector3 lightAlignedPos = Vector3.Transform(obj.worldBoundingSphereCenter, lightTransform);
                    Vector3 rad = new Vector3(obj.worldBoundingSphereRadius);
                    Vector3 localMin = lightAlignedPos - rad;
                    Vector3 localMax = lightAlignedPos + rad;

                    if (localMin.Z < castersLightBB.Min.Z) {
                        if (OpenTKHelper.RectsOverlap(castersLightBB.Min.Xy,
                                                      castersLightBB.Max.Xy,
                                                      localMin.Xy,
                                                      localMax.Xy)) {
                            castersLightBB.Min.Z = localMin.Z;
                        }
                    }
                }
            }

            // Generate frustum culler from the BB extended towards light to include shadow casters
            Matrix4 frustumView, frustumProj;
            viewProjFromLightAlignedBB(ref castersLightBB, ref lightTransform, ref lightY,
                                       out frustumView, out frustumProj);
            Matrix4 frustumMatrix = frustumView * frustumProj;
            FrustumCuller = new SSFrustumCuller (ref frustumMatrix);
        }
예제 #34
0
        internal void addObject(SSBVHNodeAdaptor <GO> nAda, GO newOb, ref SSAABB newObBox, float newObSAH)
        {
            if (gobjects != null)
            {
                // add the object and map it to our leaf
                gobjects.Add(newOb);
                nAda.mapObjectToBVHLeaf(newOb, this);
                refitVolume(nAda);
                // split if necessary...
                splitIfNecessary(nAda);
            }
            else
            {
                // find the best way to add this object.. 3 options..
                // 1. send to left node  (L+N,R)
                // 2. send to right node (L,R+N)
                // 3. merge and pushdown left-and-right node (L+R,N)

                float leftSAH               = SAH(left);
                float rightSAH              = SAH(right);
                float sendLeftSAH           = rightSAH + SAH(left.box.ExpandedBy(newObBox)); // (L+N,R)
                float sendRightSAH          = leftSAH + SAH(right.box.ExpandedBy(newObBox)); // (L,R+N)
                float mergedLeftAndRightSAH = SAH(AABBofPair(left, right)) + newObSAH;       // (L+R,N)

                // Doing a merge-and-pushdown can be expensive, so we only do it if it's notably better
                const float MERGE_DISCOUNT = 0.3f;

                if (mergedLeftAndRightSAH < (Math.Min(sendLeftSAH, sendRightSAH)) * MERGE_DISCOUNT)
                {
                    // merge and pushdown left and right as a new node..
                    var mSubnode = new ssBVHNode <GO>(nAda.BVH);
                    mSubnode.left     = left;
                    mSubnode.right    = right;
                    mSubnode.parent   = this;
                    mSubnode.gobjects = null; // we need to be an interior node... so null out our object list..
                    left.parent       = mSubnode;
                    right.parent      = mSubnode;
                    mSubnode.childRefit(nAda, recurse: false);

                    // make new subnode for obj
                    var nSubnode = new ssBVHNode <GO>(nAda.BVH);
                    nSubnode.parent   = this;
                    nSubnode.gobjects = new List <GO> {
                        newOb
                    };
                    nAda.mapObjectToBVHLeaf(newOb, nSubnode);
                    nSubnode.computeVolume(nAda);

                    // make assignments..
                    this.left  = mSubnode;
                    this.right = nSubnode;
                    this.setDepth(this.depth); // propagate new depths to our children.
                    this.childRefit(nAda);
                }
                else
                {
                    if (sendLeftSAH < sendRightSAH)
                    {
                        // send left
                        left.addObject(nAda, newOb, ref newObBox, newObSAH);
                    }
                    else
                    {
                        // send right
                        right.addObject(nAda, newOb, ref newObBox, newObSAH);
                    }
                }
            }
        }