Esempio n. 1
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);
        }
            /// <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 < m_runtimeMesh.numVertices; ++v)
                {
                    // position
                    Vector3 pos = m_runtimeMesh.computeVertexPos(v);
                    m_vertices [v].Position = pos;
                    aabb.UpdateMin(pos);
                    aabb.UpdateMax(pos);
                    // normal
                    m_vertices [v].Normal = m_runtimeMesh.computeVertexNormal(v);
                }
                vbo.UpdateBufferData(m_vertices);
                return(aabb);
            }
Esempio n. 3
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
        }
        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();
        }
Esempio n. 5
0
        }         // fn

        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);
        }
Esempio n. 6
0
 public bool IntersectsAABB(SSAABB aabb)
 {
     return(aabb.IntersectsSphere(this));
 }
        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);
        }
Esempio n. 8
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)
            SSFrustumCuller cameraFrustum = new SSFrustumCuller(ref cameraViewProj);

            foreach (var obj in objects)
            {
                // pass through all shadow casters and receivers
                if (obj.renderState.toBeDeleted || !obj.renderState.visible ||
                    !obj.renderState.receivesShadows || obj.localBoundingSphereRadius <= 0f)
                {
                    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.renderState.visible ||
                    !obj.renderState.castsShadow || obj.localBoundingSphereRadius <= 0f)
                {
                    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 SSFrustumCuller(ref frustumMatrix);
        }
Esempio n. 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));
        }