Collision Vertex? for interactive water and cloth

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
JHOW
Posts: 9
Joined: Mon Oct 26, 2009 12:52 am

Collision Vertex? for interactive water and cloth

Post by JHOW »

I have been working on a game that takes place in a pool so interactive water was a must. I have it fully working but it lags bad if i decrease the spacing in the water grid. I want to have the water vertices which are currently spheres without drawable models because you don't want to see them. Is there a way to make a class for a single vertex instead of a primitive? I eventually want to do the collision on the shader for really high definition water.

Here is a video of it working in my game.
And i have the class file for the water.
to use it just type this: Water water = new Water(space);
You also need to have Constraint drawing enabled.

As a bonus i am also giving out my cloth class. It is useful and good to learn from.
It is also destructible.

http://www.youtube.com/user/HaloRiderJH ... v3ybjX6D6k

This one may or may not be visible to some people because it is on facebook but it shows the water grid before i added the shader.
It should be visible because it is set to public but sorry if it isn't.

http://www.facebook.com/profile.php?v=a ... 9136168746

Code: Select all

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using BEPUphysics;
using System.Diagnostics;
using System.Threading;
using BEPUphysics.BroadPhases;
using BEPUphysics.Entities;
using BEPUphysics.Constraints;
using BEPUphysics.ForceFields;
using BEPUphysics.DataStructures;
using System.Collections;

namespace BEPUphysicsDemos
{
    public class Water
    {
        public List<Spring> surfaceTensionSprings;
        public List<Spring> densitySprings;
        public float surfaceTension = 0.6f;
        public float density = 0.6f;
        public List<Entity> waterTris;
        public List<WaterVertex> waterVertices;
                  
        public int wLength = 40;
        public int wWidth = 40;
        float radius = 0.0001f;
        float waterDensity = 5;
        float strength = float.MaxValue;
        Spring spring;
        Sphere sphere;
        
        Space space;

        public Water(Space space)
        {   
            this.space = space;
            BuildWater();
        }

        public void BuildWater()
        {
           
            waterVertices = new List<WaterVertex>();
            waterTris = new List<Entity>();
            surfaceTensionSprings = new List<Spring>();
            densitySprings = new List<Spring>();

            generateWaterGrid();
            setupSprings();
        }
        
        public void generateWaterGrid()
        {
            for (int i = 0; i < wWidth; i+= Convert.ToInt32(0.6f))
            {
                for (int j = 0; j < wLength; j += Convert.ToInt32(0.6f))
                {
                    sphere = new Sphere(new Vector3(i, 0, j), radius,waterDensity);
                    sphere.allowedPenetration = 1000;
                    WaterVertex vertex = new WaterVertex(sphere);
                    
                    space.add(sphere);
                    waterVertices.Add(vertex);
                }

            }
        }
        public void setupSprings()
        {
            int counter = 0;
            for (int i = 0; i < wWidth; i++)
            {
                for (int j = 0; j < wLength; j++)
                {


                    if (j != 0 && j < wLength - 1)
                    {
                        spring = new Spring(waterVertices[counter].sphere, waterVertices[counter - 1].sphere,
                        new Vector3(waterVertices[counter].sphere.worldTransform.M41, waterVertices[counter].sphere.worldTransform.M42, waterVertices[counter].sphere.worldTransform.M43),
                        new Vector3(waterVertices[counter - 1].sphere.worldTransform.M41, waterVertices[counter - 1].sphere.worldTransform.M42, waterVertices[counter - 1].sphere.worldTransform.M43),
                        5000, surfaceTension, strength, strength, strength);

                        space.add(spring);

                        surfaceTensionSprings.Add(spring);
                    }

                    if (j < wLength - 1)
                    {
                        spring = new Spring(waterVertices[counter].sphere, waterVertices[counter + 1].sphere,
                        new Vector3(waterVertices[counter].sphere.worldTransform.M41, waterVertices[counter].sphere.worldTransform.M42, waterVertices[counter].sphere.worldTransform.M43),
                        new Vector3(waterVertices[counter + 1].sphere.worldTransform.M41, waterVertices[counter + 1].sphere.worldTransform.M42, waterVertices[counter + 1].sphere.worldTransform.M43),
                        5000, surfaceTension, strength, strength, strength);

                        space.add(spring);

                        surfaceTensionSprings.Add(spring);
                    }

                    if ((counter + wLength) <  waterVertices.Count) 
                    {
                        spring = new Spring(waterVertices[counter].sphere, waterVertices[counter + wLength].sphere,
                        new Vector3(waterVertices[counter].sphere.worldTransform.M41, waterVertices[counter].sphere.worldTransform.M42, waterVertices[counter].sphere.worldTransform.M43),
                        new Vector3(waterVertices[counter + wLength].sphere.worldTransform.M41, waterVertices[counter + wLength].sphere.worldTransform.M42, waterVertices[counter + wLength].sphere.worldTransform.M43), 
                        5000, surfaceTension, strength, strength, strength);

                        space.add(spring);
                    

                        surfaceTensionSprings.Add(spring);
                    }

                    spring = new Spring(null, waterVertices[counter].sphere,
                        new Vector3(waterVertices[counter].sphere.worldTransform.M41, waterVertices[counter].sphere.worldTransform.M42, waterVertices[counter].sphere.worldTransform.M43),
                        new Vector3(waterVertices[counter].sphere.worldTransform.M41, waterVertices[counter].sphere.worldTransform.M42, waterVertices[counter].sphere.worldTransform.M43), 
                        160, density, strength, strength, strength);
                    space.add(spring);
                    densitySprings.Add(spring);
                    /*
                    if ((counter + wLength) <  waterVertices.Count && j != 0 && j < wLength - 1)
                    {
                        tri = new Triangle(new Vector3( waterVertices[counter].worldTransform.M41,  waterVertices[counter].worldTransform.M42,  waterVertices[counter].worldTransform.M43),
                            new Vector3( waterVertices[counter + 1].worldTransform.M41,  waterVertices[counter + 1].worldTransform.M42,  waterVertices[counter + 1].worldTransform.M43),
                            new Vector3( waterVertices[counter + wLength].worldTransform.M41,  waterVertices[counter + wLength].worldTransform.M42,  waterVertices[counter + wLength].worldTransform.M43),10);
                        space.add(tri);
                        waterTris.Add(tri);
                    }
                    */
                    counter++;
                }

            }
        }
    }
}
Water vertex class

Code: Select all

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using BEPUphysics;
using System.Diagnostics;
using System.Threading;
using BEPUphysics.BroadPhases;
using BEPUphysics.Entities;
using BEPUphysics.Constraints;
using BEPUphysics.ForceFields;
using BEPUphysics.DataStructures;
using System.Collections;

namespace BEPUphysicsDemos
{
    public class WaterVertex
    {
        //public Vector3 position;
        public Sphere sphere;

        public WaterVertex(Sphere sphere)
        {
            this.sphere = sphere;
        }
        public Vector3 GetPosition()
        {
            return new Vector3(sphere.worldTransform.M41, sphere.worldTransform.M42, sphere.worldTransform.M43);
        }
    }
}
Cloth

Code: Select all

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using BEPUphysics;
using System.Diagnostics;
using System.Threading;
using BEPUphysics.BroadPhases;
using BEPUphysics.Entities;
using BEPUphysics.Constraints;
using BEPUphysics.ForceFields;
using BEPUphysics.DataStructures;
using System.Collections;

namespace BEPUphysicsDemos
{
    public class Cloth
    {
        public List<Spring> surfaceTensionSprings;       
        public float surfaceTension = 3f;
        public List<Entity> vertices;

        public int wLength = 25;
        public int wWidth = 25;
        float radius = 0.0001f;
        float density = 10;
        float strength = 9000;
        Spring spring;
        Sphere sphere;
        
        Space space;

        public Cloth(Space space)
        {   
            this.space = space;
            BuildWater();
        }

        public void BuildWater()
        {
           
            vertices = new List<Entity>();
            surfaceTensionSprings = new List<Spring>();
            
            generateClothGrid();
            setupSprings();
        }
        float scale = 1f;
        public void generateClothGrid()
        {
            float xOffset = -wWidth * 0.5f;
            float zOffset = -wLength * 0.5f;

            for (int i = 0; i < wWidth; i+= Convert.ToInt32(scale))
            {
                for (int j = 0; j < wLength; j += Convert.ToInt32(scale))
                {
                    if (i == 0)
                    {
                        sphere = new Sphere(new Vector3(i + xOffset, 0, j + zOffset), radius);
                        space.add(sphere);
                    }
                    /*
                    else if (i == wWidth - 1)
                    {
                        sphere = new Sphere(new Vector3(i + xOffset, 0, j + zOffset), radius);
                        space.add(sphere);
                    }
                    */
                    else
                    {
                        sphere = new Sphere(new Vector3(i + xOffset, 0, j + zOffset), radius, density);
                        space.add(sphere);
                    }
                    vertices.Add(sphere);
                }

            }
        }
        public void setupSprings()
        {
            int counter = 0;
            for (int i = 0; i < wWidth; i++)
            {
                for (int j = 0; j < wLength; j++)
                {


                    if (j != 0 && j < wLength - 1)
                    {
                        spring = new Spring(vertices[counter], vertices[counter - 1],
                        new Vector3(vertices[counter].worldTransform.M41, vertices[counter].worldTransform.M42, vertices[counter].worldTransform.M43),
                        new Vector3(vertices[counter - 1].worldTransform.M41, vertices[counter - 1].worldTransform.M42, vertices[counter - 1].worldTransform.M43),
                        1000, surfaceTension, strength, strength, strength);

                        space.add(spring);

                        surfaceTensionSprings.Add(spring);
                    }

                    if (j < wLength - 1)
                    {
                        spring = new Spring(vertices[counter], vertices[counter + 1],
                        new Vector3(vertices[counter].worldTransform.M41, vertices[counter].worldTransform.M42, vertices[counter].worldTransform.M43),
                        new Vector3(vertices[counter + 1].worldTransform.M41, vertices[counter + 1].worldTransform.M42, vertices[counter + 1].worldTransform.M43),
                        1000, surfaceTension, strength, strength, strength);

                        space.add(spring);

                        surfaceTensionSprings.Add(spring);
                    }

                    if ((counter + wLength) <  vertices.Count) 
                    {
                        spring = new Spring(vertices[counter], vertices[counter + wLength],
                        new Vector3(vertices[counter].worldTransform.M41, vertices[counter].worldTransform.M42, vertices[counter].worldTransform.M43),
                        new Vector3(vertices[counter + wLength].worldTransform.M41, vertices[counter + wLength].worldTransform.M42, vertices[counter + wLength].worldTransform.M43), 
                        1000, surfaceTension, strength, strength, strength);

                        space.add(spring);
                    

                        surfaceTensionSprings.Add(spring);
                    }

                    
                    counter++;
                }

            }
        }
    }
}
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Collision Vertex? for interactive water and cloth

Post by Norbo »

Interesting approach to water! I had fun playing around with both :)

As it turns out, there were some issues preventing the creation of a 'VertexEntity' which have been fixed in the just-released v0.10.2. So yes, you can create a pointmass entity type now. I went ahead and set up an example VertexEntity and successfully tested it with your water and cloth. I've attached the source code for it.
Attachments
VertexEntity.zip
(1.68 KiB) Downloaded 282 times
JHOW
Posts: 9
Joined: Mon Oct 26, 2009 12:52 am

Re: Collision Vertex? for interactive water and cloth

Post by JHOW »

Thank you so much for your help. That made the frame rate go up. Now my next task is to figure out how to do the physics on the shader itself. I know how to calculate the spring physics but would you have any idea how to handle collision detection on a shader?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Collision Vertex? for interactive water and cloth

Post by Norbo »

That's a field of pretty active research still. It would depend on what kind of specific collision detection you want, and what information you'd want in the end. If you wanted to supply collision constraints or something like them to BEPUphysics (or a physics engine in general), you would need contact point location (easy), normal (could be easy if you cheat, hard otherwise), and penetration depth (hard unless cheating again).

If you can restrict it to a small number of spheres colliding with the particles, the collision detection logic is pretty straightforward- locations are the particle locations, normals are the normalized offsets from the particle to the center of the sphere, and depth is the radius of the sphere minus the distance between the particle and center of the sphere. Textures would encode the data (position) of the particles and spheres, as well as the output. This is basically the brute force approach, so it could be made significantly faster if you added a lot of complexity to it.

In the end the outputs of this may be best kept out of the actual solver, instead you could arbitrarily apply forces based on the collision detection data which approximate the collision. It's not like you need *rigid* body penetration constraints for water :)
JHOW
Posts: 9
Joined: Mon Oct 26, 2009 12:52 am

Re: Collision Vertex? for interactive water and cloth

Post by JHOW »

I read what you said and im starting to think that the lag is occurring because of all the springs. What if i pass the shader a Vector3 array holding all the vertex positions and just have the shader calculate the spring physics using the positions of the vertexes around it.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Collision Vertex? for interactive water and cloth

Post by Norbo »

Here's a relevant paper:
http://wwwcg.in.tum.de/Research/data/Pu ... mpra05.pdf

The spring simulation is indeed likely the source of most of the slowdown. Of course, trying to map things to the GPU is never completely easy :)
Post Reply