Esempio n. 1
0
        /// <summary>
        /// Test if terrain intersects a sub-rect of terrain.
        /// </summary>
        private void RayIntersectsTerrain(Intersection.ObjectIntersection <QuadNode> ni, out TerrainIntersectionData terrainCollisionData)
        {
            // Get node
            QuadNode node = ni.Object;

            // Transform ray back to object space
            Ray    ray;
            Matrix inverseTransform = Matrix.Invert(node.WorldMatrix);

            ray.Position  = Vector3.Transform(core.Renderer.PointerRay.Position, inverseTransform);
            ray.Direction = Vector3.TransformNormal(core.Renderer.PointerRay.Direction, inverseTransform);

            int     index;
            float   height      = 0;
            Vector2 position    = Vector2.Zero;
            int     loopCounter = 0;
            Vector3 step        = ray.Direction * 1f;
            bool    found       = false;

            while (true)
            {
                // Step ray along direction
                ray.Position += step;

                // Break loop if running too long
                if (++loopCounter > 5000)
                {
                    found = false;
                    break;
                }

                // Get position
                position.X = ray.Position.X + node.Rectangle.X;
                position.Y = ray.Position.Z + node.Rectangle.Y;
                if (position.X < 0 || position.X > mapDimension - 1 ||
                    position.Y < 0 || position.Y > mapDimension - 1)
                {
                    found = false;
                    continue;
                }

                // If we've come this far then an intersection is likely
                found = true;

                // Get index into arrays
                index = (int)position.Y * (int)mapDimension + (int)position.X;

                // Get height of terrain at this position
                height = terrainData[index].W * mapHeight;
                if (ray.Position.Y <= height)
                {
                    ray.Position -= step;
                    break;
                }
            }

            // Exit if no intersection found
            if (!found)
            {
                terrainCollisionData.Distance      = null;
                terrainCollisionData.WorldPosition = Vector3.Zero;
                terrainCollisionData.MapPosition   = Vector2.Zero;
                return;
            }

            // Store map collision in 0,1 space
            terrainCollisionData.MapPosition.X = position.X / mapDimension;
            terrainCollisionData.MapPosition.Y = position.Y / mapDimension;

            // Store world collision in world space
            Vector3 worldPosition = new Vector3
            {
                X = position.X,
                Y = height,
                Z = position.Y,
            };

            terrainCollisionData.WorldPosition = Vector3.Transform(worldPosition, this.Matrix);

            // Set distance
            terrainCollisionData.Distance = Vector3.Distance(core.ActiveScene.Camera.Position, terrainCollisionData.WorldPosition);
        }
Esempio n. 2
0
        /// <summary>
        /// Draw this node and all child nodes.
        /// </summary>
        /// <param name="node">Node to draw.</param>
        /// <param name="caller">Entity calling the draw operation.</param>
        private void DrawNode(QuadNode node, BaseEntity caller)
        {
            if (node == null)
            {
                return;
            }

            // Calculate world matrix
            node.WorldMatrix = node.Matrix * this.matrix * Matrix.CreateTranslation(caller.Matrix.Translation);

            // Transform bounds for this node
            BoundingBox bounds;

            bounds.Min = Vector3.Transform(node.BoundingBox.Min, node.WorldMatrix);
            bounds.Max = Vector3.Transform(node.BoundingBox.Max, node.WorldMatrix);

            // Test node against frustum
            if (!bounds.Intersects(core.ActiveScene.Camera.BoundingFrustum))
            {
                return;
            }

            // Recurse children
            foreach (QuadNode child in node.Children)
            {
                DrawNode(child, caller);
            }

            // Calculate sample scale
            Vector2 sampleScale;

            sampleScale.X = (float)leafDimension / (float)mapDimension;
            sampleScale.Y = sampleScale.X;

            // Only draw terrain grid for leaf nodes
            if (!node.HasChildren)
            {
                if (enablePicking)
                {
                    // Test for node-ray intersection
                    float?intersectDistance = core.Renderer.PointerRay.Intersects(bounds);
                    if (intersectDistance != null)
                    {
                        // Add to intersection list
                        Intersection.ObjectIntersection <QuadNode> ni =
                            new Intersection.ObjectIntersection <QuadNode>(intersectDistance, node);
                        pointerNodeIntersections.Add(ni);
                    }
                }

                // Calculate sample offset
                Vector2 sampleOffset;
                sampleOffset.X = node.X / mapDimension;
                sampleOffset.Y = node.Y / mapDimension;

                // Set effect parameters for this quad
                terrainEffect_SampleScale.SetValue(sampleScale);
                terrainEffect_SampleOffset.SetValue(sampleOffset);
                terrainEffect_World.SetValue(node.WorldMatrix);

                // Apply effect
                terrainEffect.Techniques[0].Passes[0].Apply();

                // Draw grid
                core.GraphicsDevice.SetVertexBuffer(grid.VertexBuffer);
                core.GraphicsDevice.Indices = grid.IndexBuffer;
                core.GraphicsDevice.DrawIndexedPrimitives(
                    PrimitiveType.TriangleList,
                    0,
                    0,
                    grid.VertexBuffer.VertexCount,
                    0,
                    grid.IndexBuffer.IndexCount / 3);
            }
        }