Result from a terrain ray intersection with the terrain group.
Example #1
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="distanceLimit"></param>
        /// <returns></returns>
        public RayResult RayIntersects(Ray ray, float distanceLimit)
        {
            long curr_x = 0, curr_z = 0;
            ConvertWorldPositionToTerrainSlot(ray.Origin, out curr_x, out curr_z);
            TerrainSlot slot = GetTerrainSlot(curr_x, curr_z);

            RayResult result = new RayResult(false, null, Vector3.Zero);

            Vector3 tmp, localRayDir, centreOrigin, offset;
            tmp = localRayDir = centreOrigin = offset = Vector3.Zero;
            ConvertTerrainSlotToWorldPosition(curr_x, curr_z, out centreOrigin);
            offset = ray.Origin - centreOrigin;
            localRayDir = ray.Direction;
            switch (Alignment)
            {
                case Alignment.Align_X_Y:
                    float t1 = localRayDir.x, t2 = localRayDir.z;
                    Swap(t1, t2);
                    localRayDir = new Vector3(t1, localRayDir.y, t2);
                    t1 = offset.x;
                    t2 = offset.z;
                    Swap(t1, t2);
                    localRayDir = new Vector3(t1, offset.y, t2);
                    break;
                case Alignment.Align_Y_Z:
                    // x = z, z = y, y = -x
                    tmp.x = localRayDir.z; 
                    tmp.z = localRayDir.y; 
                    tmp.y = -localRayDir.x; 
                    localRayDir = tmp;
                    tmp.x = offset.z; 
                    tmp.z = offset.y; 
                    tmp.y = -offset.x; 
                    offset = tmp;
                    break;
                case Alignment.Align_X_Z:
                    // already in X/Z but values increase in -Z
                    localRayDir.z = -localRayDir.z;
                    offset.z = -offset.z;
                    break;
            }

            offset /= _terrainWorldSize;
            offset = new Vector3(offset.x +0.5f,offset.y + 0.5f, offset.z +0.5f);
            Vector3 inc = new Vector3(Math.Utility.Abs(localRayDir.x), Math.Utility.Abs(localRayDir.y), Math.Utility.Abs(localRayDir.z));
            long xdir = localRayDir.x > 0.0f ? 1 : -1;
            long zdir = localRayDir.z > 0.0f ? 1 : -1;

            // We're always counting from 0 to 1 regardless of what direction we're heading
	                if (xdir < 0)
	                        offset.x = 1.0f - offset.x;
	                if (zdir < 0)
	                        offset.z = 1.0f - offset.z;
	
	                // find next slot
	                bool keepSearching = true;
	                int numGaps = 0;
                    while (keepSearching)
                    {
                        if (Math.Utility.RealEqual(inc.x, 0.0f) && Math.Utility.RealEqual(inc.z, 0.0f))
                            keepSearching = false;

                        while ((slot != null || slot.Instance != null) && keepSearching)
                        {
                            ++numGaps;
                            /// if we don't find any filled slot in 6 traversals, give up
                            if (numGaps > 6)
                            {
                                keepSearching = false;
                                break;
                            }
                            // find next slot
                            Vector3 oldoffset = offset;
                            while (offset.x < 1.0f && offset.z < 1.0f)
                                offset += inc;
                            if (offset.x >= 1.0f && offset.z >= 1.0f)
                            {
                                // We crossed a corner, need to figure out which we passed first
                                Real diffz = 1.0f - oldoffset.z;
                                Real diffx = 1.0f - oldoffset.x;
                                Real distz = diffz / inc.z;
                                Real distx = diffx / inc.x;
                                if (distx < distz)
                                {
                                    curr_x += xdir;
                                    offset.x -= 1.0f;
                                }
                                else
                                {
                                    curr_z += zdir;
                                    offset.z -= 1.0f;
                                }

                            }
                            else if (offset.x >= 1.0f)
                            {
                                curr_x += xdir;
                                offset.x -= 1.0f;
                            }
                            else if (offset.z >= 1.0f)
                            {
                                curr_z += zdir;
                                offset.z -= 1.0f;
                            }
                            if (distanceLimit > 0)
                            {
                                Vector3 worldPos;
                                ConvertTerrainSlotToWorldPosition(curr_x, curr_z, out worldPos);
                                if (ray.Origin.Distance(worldPos) > distanceLimit)
                                {
                                    keepSearching = false;
                                    break;
                                }
                            }
                            slot = GetTerrainSlot(curr_x, curr_z);
                        }
                        if (slot != null && slot.Instance != null)
                        {
                            numGaps = 0;
                            // don't cascade into neighbours
                            KeyValuePair<bool, Vector3> raypair = slot.Instance.RayIntersects(ray, false, distanceLimit);
                            if (raypair.Key)
                            {
                                keepSearching = false;
                                result.Hit = true;
                                result.Terrain = slot.Instance;
                                result.Position = raypair.Value;
                                break;
                            }
                            else
                            {
                                // not this one, trigger search for another slot
                                slot = null;
                            }
                        }

                    }
	
	
	                return result;
        }