Partage
  • Partager sur Facebook
  • Partager sur Twitter

[XNA] Collision avec une heighmap

    14 août 2011 à 16:09:18

    Bonjours a tous et a toutes,

    Voila mon problème, j'ai généré une terrain grave a une heigtmap en c# XNA
    Mais le souci c'est que j'aimerais mettre en place une gestion des collision entre mon terrain générer et ma caméra

    Si joins le projet Visual Studio 2010 XNA

    http://www.megaupload.com/?d=OCZHDM7P

    Et pour ceux qui aurons la flemme de télécharger le projet Voici le code source (oui tout est dans la meme classe c'est du salle, je découperais une fois que les collisions seront faites et que j'aurais bien compris ;)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Content;
    using Microsoft.Xna.Framework.GamerServices;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Media;
    
    namespace Series3D1
    {
        public class Game1 : Microsoft.Xna.Framework.Game
        {
            GraphicsDeviceManager graphics;
            SpriteBatch spriteBatch;
            GraphicsDevice device;
    
    
            Effect effect;
            VertexPositionColorNormal[] vertices;
            Matrix viewMatrix;
            Matrix projectionMatrix;
            Texture2D heightMap;
    
    
            Vector3 cameraPosition;
            MouseState originalMouseState;
    
            int[] indices;
    
        
    
            float leftrightRot;
            float upDownRot;
            float rotationSpeed;
            float moveSpeed;
            private float angle = 0f;
            private int terrainWidth = 4;
            private int terrainHeight = 3;
            private float[,] heightData;
            private bool h;
            private bool wire;
    
    
    
            public struct VertexPositionColorNormal
            {
                public Vector3 Position;
                public Color Color;
                public Vector3 Normal;
    
                public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
                (
                    new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
                    new VertexElement(sizeof(float) * 3, VertexElementFormat.Color, VertexElementUsage.Color, 0),
                    new VertexElement(sizeof(float) * 3 + 4, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0)
                );
            }
    
    
            public Game1()
            {
                graphics = new GraphicsDeviceManager(this);
                Content.RootDirectory = "Content";
            }
    
            protected override void Initialize()
            {
                graphics.PreferredBackBufferWidth = 1920;
                graphics.PreferredBackBufferHeight = 1080;
                graphics.IsFullScreen = true;
                graphics.ApplyChanges();
                Window.Title = "Test";
    
                h = true;
                wire = false;
               
                cameraPosition = new Vector3(60, 100, 50);
                leftrightRot = MathHelper.PiOver2;
                upDownRot = -MathHelper.Pi / 10.0f;
                rotationSpeed = 0.3f;
                moveSpeed = 30.0f;
    
    
                base.Initialize();
            }
    
            protected override void LoadContent()
            {
                spriteBatch = new SpriteBatch(GraphicsDevice);
    
                device = graphics.GraphicsDevice;
    
                effect = Content.Load<Effect>("effects");
                UpdateViewMatrix();
    
    
    
                heightMap = Content.Load<Texture2D>("heightmap"); 
                LoadHeightData(heightMap);
    
                SetUpVertices();
                SetUpIndices();
                CalculateNormals();
    
                Mouse.SetPosition(device.Viewport.Width / 2, device.Viewport.Height / 2);
                originalMouseState = Mouse.GetState();
            }
    
            protected override void UnloadContent()
            {
            }
    
            private void SetUpVertices()
            {
    
                float minHeight = float.MaxValue;
                float maxHeight = float.MinValue;
    
                for (int x = 0; x < terrainWidth; x++)
                {
                    for (int y = 0; y < terrainHeight; y++)
                    {
                        if (heightData[x, y] < minHeight)
                            minHeight = heightData[x, y];
                        if (heightData[x, y] > maxHeight)
                            maxHeight = heightData[x, y];
                    }
                }
    
                vertices = new VertexPositionColorNormal[terrainWidth * terrainHeight];
                for (int x = 0; x < terrainWidth; x++)
                {
                    for (int y = 0; y < terrainHeight; y++)
                    {
                        if(h)
                             vertices[x + y * terrainWidth].Position = new Vector3(x, heightData[x, y], -y);
                        else
                            vertices[x + y * terrainWidth].Position = new Vector3(x, minHeight, -y);
    
                        if (heightData[x, y] < minHeight + (maxHeight - minHeight) / 4)
                            vertices[x + y * terrainWidth].Color = Color.Blue;
                        else if (heightData[x, y] < minHeight + (maxHeight - minHeight) * 2 / 4)
                            vertices[x + y * terrainWidth].Color = Color.Green;
                        else if (heightData[x, y] < minHeight + (maxHeight - minHeight) * 3 / 4)
                            vertices[x + y * terrainWidth].Color = Color.Brown;
                        else
                            vertices[x + y * terrainWidth].Color = Color.White;
    
                    }
                }
            }
    
            private void SetUpIndices()
            {
                indices = new int[(terrainWidth - 1) * (terrainHeight - 1) * 6];
                int counter = 0;
                for (int y = 0; y < terrainHeight - 1; y++)
                {
                    for (int x = 0; x < terrainWidth - 1; x++)
                    {
                        int lowerLeft = x + y * terrainWidth;
                        int lowerRight = (x + 1) + y * terrainWidth;
                        int topLeft = x + (y + 1) * terrainWidth;
                        int topRight = (x + 1) + (y + 1) * terrainWidth;
    
                        indices[counter++] = topLeft;
                        indices[counter++] = lowerRight;
                        indices[counter++] = lowerLeft;
    
                        indices[counter++] = topLeft;
                        indices[counter++] = topRight;
                        indices[counter++] = lowerRight;
                    }
                }
            }
    
            private void LoadHeightData(Texture2D heightMap)
            {
                terrainWidth = heightMap.Width;
                terrainHeight = heightMap.Height;
    
                Color[] heightMapColors = new Color[terrainWidth * terrainHeight];
                heightMap.GetData(heightMapColors);
    
                heightData = new float[terrainWidth, terrainHeight];
                for (int x = 0; x < terrainWidth; x++)
                    for (int y = 0; y < terrainHeight; y++)
                        heightData[x, y] = heightMapColors[x + y * terrainWidth].R / 5.0f;
            }
    
           
    
            private void UpdateViewMatrix()
            {
                Matrix cameraRotation = Matrix.CreateRotationX(upDownRot) * Matrix.CreateRotationY(leftrightRot);
                Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
                Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
                Vector3 finalTarget = cameraPosition + cameraRotatedTarget;
    
                Vector3 cameraOriginalVectorUp = new Vector3(0, 1, 0);
                Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalVectorUp, cameraRotation);
    
                viewMatrix = Matrix.CreateLookAt(cameraPosition, finalTarget, cameraRotatedUpVector);
                projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 1.0f, 300.0f);
            }
    
            protected override void Update(GameTime gameTime)
            {
                if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                    this.Exit();
    
                KeyboardState keyState = Keyboard.GetState();
             
                    if (keyState.IsKeyDown(Keys.H))
                    {
                        
                            if (h == true)
                                h = false;
    
                            else
                                h = true;
                            LoadHeightData(heightMap);
                            SetUpVertices();
                            CalculateNormals();
                        
                    }
                    if (keyState.IsKeyDown(Keys.W))
                    {
                        if (wire == true)
                            wire = false;
    
                        else
                            wire = true;
                    }
    
                    float timeDifference = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
    
                    cameraInput(timeDifference);
                
                
    
                base.Update(gameTime);
            }
    
            protected override void Draw(GameTime gameTime)
            {
                device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);
    
                RasterizerState rs = new RasterizerState();
               // rs.CullMode = CullMode.None;
    
                if (wire)
                    rs.FillMode = FillMode.WireFrame;
                else
                    rs.FillMode = FillMode.Solid;
                device.RasterizerState = rs;
    
    
                Matrix worldMatrix = Matrix.CreateTranslation(-terrainWidth / 2.0f, 0, terrainHeight / 2.0f) * Matrix.CreateRotationY(angle);
                effect.CurrentTechnique = effect.Techniques["Colored"];
                effect.Parameters["xView"].SetValue(viewMatrix);
                effect.Parameters["xProjection"].SetValue(projectionMatrix);
                effect.Parameters["xWorld"].SetValue(worldMatrix);
                Vector3 lightDirection = new Vector3(1.0f, -1.0f, -1.0f);
                lightDirection.Normalize();
                effect.Parameters["xLightDirection"].SetValue(lightDirection);
                effect.Parameters["xAmbient"].SetValue(0.1f);
                effect.Parameters["xEnableLighting"].SetValue(true);
    
                foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                {
                    pass.Apply();
    
                    device.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, indices.Length / 3, VertexPositionColorNormal.VertexDeclaration);
                }
    
                base.Draw(gameTime);
            }
    
            private void cameraInput(float amount)
            {
    
                MouseState currentMouseState = Mouse.GetState();
                if (currentMouseState != originalMouseState)
                {
                    float xDiference = currentMouseState.X - originalMouseState.X;
                    float yDiference = currentMouseState.Y - originalMouseState.Y;
    
                    leftrightRot -= rotationSpeed * xDiference * amount;
                    upDownRot -= rotationSpeed * yDiference * amount;
                    Mouse.SetPosition(device.Viewport.Width / 2, device.Viewport.Height / 2);
                    UpdateViewMatrix();
    
                }
    
                Vector3 moveVector = new Vector3(0, 0, 0);
                KeyboardState keyState = Keyboard.GetState();
    
                if (keyState.IsKeyDown(Keys.Up) || keyState.IsKeyDown(Keys.Z))
                    moveVector += new Vector3(0, 0, -1);
                if (keyState.IsKeyDown(Keys.Down) || keyState.IsKeyDown(Keys.S))
                    moveVector += new Vector3(0, 0, 1);
                if (keyState.IsKeyDown(Keys.Right) || keyState.IsKeyDown(Keys.D))
                    moveVector += new Vector3(1, 0, 0);
                if (keyState.IsKeyDown(Keys.Left) || keyState.IsKeyDown(Keys.Q))
                    moveVector += new Vector3(-1, 0, 0);
                if (keyState.IsKeyDown(Keys.A))
                    moveVector += new Vector3(0, 1, 0);
                if (keyState.IsKeyDown(Keys.E))
                    moveVector += new Vector3(0, -1, 0);
                AddToCameraPosition(moveVector * amount);
            }
    
            private void AddToCameraPosition(Vector3 vectorToAdd)
            {
                Vector3 tmp;
                Matrix cameraRotation = Matrix.CreateRotationX(upDownRot) * Matrix.CreateRotationY(leftrightRot);
                Vector3 rotatedVector = Vector3.Transform(vectorToAdd, cameraRotation);
                tmp = cameraPosition;
                cameraPosition += moveSpeed * rotatedVector;
               if (Iscolision())
               {
                   cameraPosition = tmp;
               }
                else
                UpdateViewMatrix();
            }
    
            private bool Iscolision()
            {
             
                
            
                float hauteursol;
    
               
                   
                     hauteursol =(int)getHeightValue((int)Math.Round(cameraPosition.X), (int)Math.Round(cameraPosition.Z));
                                     
                    if (hauteursol > (int)Math.Round(cameraPosition.Y))
                        return true;
                   
                        
    
                
    
                return false;
            }
    
            private float getHeightValue(int x, int y)
            {
                
    
                if (x*y>heightData.Length && x>0 && y>0)
                    return heightData[x, y];
                else return -10.0f;
            }
    
            private void CalculateNormals()
            {
                for (int i = 0; i < vertices.Length; i++)
                    vertices[i].Normal = new Vector3(0, 0, 0);
    
                for (int i = 0; i < indices.Length / 3; i++)
                {
                    int index1 = indices[i * 3];
                    int index2 = indices[i * 3 + 1];
                    int index3 = indices[i * 3 + 2];
    
                    Vector3 side1 = vertices[index1].Position - vertices[index3].Position;
                    Vector3 side2 = vertices[index1].Position - vertices[index2].Position;
                    Vector3 normal = Vector3.Cross(side1, side2);
    
                    vertices[index1].Normal += normal;
                    vertices[index2].Normal += normal;
                    vertices[index3].Normal += normal;
                }
    
                for (int i = 0; i < vertices.Length; i++)
                    vertices[i].Normal.Normalize();
            }
    
        }
    }
    


    Ma première idée était de regarder la hauteur de la caméra par rapport a la hauteur du terrain que j'ai en dessous et de comparer les 2 voir si je suis en dessous ou pas pour détecter une collision.
    Le souci c'est dans mon tableau vertices j'ai les coordonnées des différents points qui forment les triangle donc si ma caméra ce situe dans la surface d'un de ces triangle, je n'arrive pas a savoir la hauteur du terrain précise.

    Je me suis dit pourquoi pas avoir une équation qui permet de savoir si un point(par exemple ma camera) appartient a la surface d'un triangle dans l'espace (dont les sommet sont connu) mais bon impossible de trouver une telle équation

    dans tout les cas je vous remercie d’avance pour votre ide ;)
    • Partager sur Facebook
    • Partager sur Twitter
      14 août 2011 à 16:39:53

      Pour être honnête j'ai la flemme de me plonger dans tout ce code, mais je t'invites à consulter ces liens (si ce n'est déjà fait) :
      Collision Series 4: Collision with a Heightmap
      Collision Series 5: Heightmap Collision with Normals

      En bas de chaque page tu peux télécharger le code. Tu verras, le rendu est pas mal du tout !
      • Partager sur Facebook
      • Partager sur Twitter

      [XNA] Collision avec une heighmap

      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
      • Editeur
      • Markdown