XNA shield effect with a Primative sphere problem

Posted by Sparky41 on Game Development See other posts from Game Development or by Sparky41
Published on 2012-11-30T22:24:46Z Indexed on 2012/11/30 23:22 UTC
Read the original article Hit count: 294

Filed under:
|
|
|

I'm having issue with a shield effect i'm trying to develop. I want to do a shield effect that surrounds part of a model like this: http://i.imgur.com/jPvrf.png

I currently got this: http://i.imgur.com/Jdin7.png (The red likes are a simple texture a black background with a red cross in it, for testing purposes: http://i.imgur.com/ODtzk.png where the smaller cross in the middle shows the contact point)

This sphere is drawn via a primitive (DrawIndexedPrimitives)

This is how i calculate the pieces of the sphere using a class i've called Sphere

(this class is based off the code here: http://xbox.create.msdn.com/en-US/education/catalog/sample/primitives_3d)

public class Sphere { // During the process of constructing a primitive model, vertex // and index data is stored on the CPU in these managed lists. List vertices = new List(); List indices = new List();

    // Once all the geometry has been specified, the InitializePrimitive
    // method copies the vertex and index data into these buffers, which
    // store it on the GPU ready for efficient rendering.
    VertexBuffer vertexBuffer;
    IndexBuffer indexBuffer;
    BasicEffect basicEffect;

    public Vector3 position = Vector3.Zero;
    public Matrix RotationMatrix = Matrix.Identity;

    public Texture2D texture;

    /// <summary>
    /// Constructs a new sphere primitive,
    /// with the specified size and tessellation level.
    /// </summary>
    public Sphere(float diameter, int tessellation, Texture2D text, float up, float down, float portstar, float frontback)
    {
        texture = text;
        if (tessellation < 3)
            throw new ArgumentOutOfRangeException("tessellation");

        int verticalSegments = tessellation;
        int horizontalSegments = tessellation * 2;

        float radius = diameter / 2;

        // Start with a single vertex at the bottom of the sphere.
        AddVertex(Vector3.Down * ((radius / up) + 1), Vector3.Down, Vector2.Zero);//bottom position5

        // Create rings of vertices at progressively higher latitudes.
        for (int i = 0; i < verticalSegments - 1; i++)
        {
            float latitude = ((i + 1) * MathHelper.Pi /
                                        verticalSegments) - MathHelper.PiOver2;

            float dy = (float)Math.Sin(latitude / up);//(up)5
            float dxz = (float)Math.Cos(latitude);

            // Create a single ring of vertices at this latitude.
            for (int j = 0; j < horizontalSegments; j++)
            {
                float longitude = j * MathHelper.TwoPi / horizontalSegments;

                float dx = (float)(Math.Cos(longitude) * dxz) / portstar;//port and starboard (right)2
                float dz = (float)(Math.Sin(longitude) * dxz) * frontback;//front and back1.4

                Vector3 normal = new Vector3(dx, dy, dz);

                AddVertex(normal * radius, normal, new Vector2(j, i));
            }
        }

        // Finish with a single vertex at the top of the sphere.
        AddVertex(Vector3.Up * ((radius / down) + 1), Vector3.Up, Vector2.One);//top position5

        // Create a fan connecting the bottom vertex to the bottom latitude ring.
        for (int i = 0; i < horizontalSegments; i++)
        {
            AddIndex(0);
            AddIndex(1 + (i + 1) % horizontalSegments);
            AddIndex(1 + i);
        }

        // Fill the sphere body with triangles joining each pair of latitude rings.
        for (int i = 0; i < verticalSegments - 2; i++)
        {
            for (int j = 0; j < horizontalSegments; j++)
            {
                int nextI = i + 1;
                int nextJ = (j + 1) % horizontalSegments;

                AddIndex(1 + i * horizontalSegments + j);
                AddIndex(1 + i * horizontalSegments + nextJ);
                AddIndex(1 + nextI * horizontalSegments + j);

                AddIndex(1 + i * horizontalSegments + nextJ);
                AddIndex(1 + nextI * horizontalSegments + nextJ);
                AddIndex(1 + nextI * horizontalSegments + j);
            }
        }

        // Create a fan connecting the top vertex to the top latitude ring.
        for (int i = 0; i < horizontalSegments; i++)
        {
            AddIndex(CurrentVertex - 1);
            AddIndex(CurrentVertex - 2 - (i + 1) % horizontalSegments);
            AddIndex(CurrentVertex - 2 - i);
        }

        //InitializePrimitive(graphicsDevice);
    }

    /// <summary>
    /// Adds a new vertex to the primitive model. This should only be called
    /// during the initialization process, before InitializePrimitive.
    /// </summary>
    protected void AddVertex(Vector3 position, Vector3 normal, Vector2 texturecoordinate)
    {
        vertices.Add(new VertexPositionNormal(position, normal, texturecoordinate));
    }


    /// <summary>
    /// Adds a new index to the primitive model. This should only be called
    /// during the initialization process, before InitializePrimitive.
    /// </summary>
    protected void AddIndex(int index)
    {
        if (index > ushort.MaxValue)
            throw new ArgumentOutOfRangeException("index");

        indices.Add((ushort)index);
    }


    /// <summary>
    /// Queries the index of the current vertex. This starts at
    /// zero, and increments every time AddVertex is called.
    /// </summary>
    protected int CurrentVertex
    {
        get { return vertices.Count; }
    }

    public void InitializePrimitive(GraphicsDevice graphicsDevice)
    {
        // Create a vertex declaration, describing the format of our vertex data.

        // Create a vertex buffer, and copy our vertex data into it.
        vertexBuffer = new VertexBuffer(graphicsDevice,
                                        typeof(VertexPositionNormal),
                                        vertices.Count, BufferUsage.None);

        vertexBuffer.SetData(vertices.ToArray());

        // Create an index buffer, and copy our index data into it.
        indexBuffer = new IndexBuffer(graphicsDevice, typeof(ushort),
                                      indices.Count, BufferUsage.None);

        indexBuffer.SetData(indices.ToArray());

        // Create a BasicEffect, which will be used to render the primitive.
        basicEffect = new BasicEffect(graphicsDevice);
        //basicEffect.EnableDefaultLighting();
    }

    /// <summary>
    /// Draws the primitive model, using the specified effect. Unlike the other
    /// Draw overload where you just specify the world/view/projection matrices
    /// and color, this method does not set any renderstates, so you must make
    /// sure all states are set to sensible values before you call it.
    /// </summary>
    public void Draw(Effect effect)
    {
        GraphicsDevice graphicsDevice = effect.GraphicsDevice;

        // Set our vertex declaration, vertex buffer, and index buffer.
        graphicsDevice.SetVertexBuffer(vertexBuffer);

        graphicsDevice.Indices = indexBuffer;

        graphicsDevice.BlendState = BlendState.Additive;

        foreach (EffectPass effectPass in effect.CurrentTechnique.Passes)
        {
            effectPass.Apply();

            int primitiveCount = indices.Count / 3;

            graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0,
                                                 vertices.Count, 0, primitiveCount);

        }
        graphicsDevice.BlendState = BlendState.Opaque;
    }


    /// <summary>
    /// Draws the primitive model, using a BasicEffect shader with default
    /// lighting. Unlike the other Draw overload where you specify a custom
    /// effect, this method sets important renderstates to sensible values
    /// for 3D model rendering, so you do not need to set these states before
    /// you call it.
    /// </summary>
    public void Draw(Camera camera, Color color)
    {
        // Set BasicEffect parameters.
        basicEffect.World = GetWorld();
        basicEffect.View = camera.view;
        basicEffect.Projection = camera.projection;
        basicEffect.DiffuseColor = color.ToVector3();
        basicEffect.TextureEnabled = true;
        basicEffect.Texture = texture;


        GraphicsDevice device = basicEffect.GraphicsDevice;
        device.DepthStencilState = DepthStencilState.Default;

        if (color.A < 255)
        {
            // Set renderstates for alpha blended rendering.
            device.BlendState = BlendState.AlphaBlend;
        }
        else
        {
            // Set renderstates for opaque rendering.
            device.BlendState = BlendState.Opaque;
        }

        // Draw the model, using BasicEffect.
        Draw(basicEffect);
    }

    public virtual Matrix GetWorld()
    {
        return /*world */ Matrix.CreateScale(1f) * RotationMatrix * Matrix.CreateTranslation(position);
    }
}



public struct VertexPositionNormal : IVertexType
{
    public Vector3 Position;
    public Vector3 Normal;
    public Vector2 TextureCoordinate;


    /// <summary>
    /// Constructor.
    /// </summary>
    public VertexPositionNormal(Vector3 position, Vector3 normal, Vector2 textCoor)
    {
        Position = position;
        Normal = normal;
        TextureCoordinate = textCoor;
    }

    /// <summary>
    /// A VertexDeclaration object, which contains information about the vertex
    /// elements contained within this struct.
    /// </summary>
    public static readonly VertexDeclaration VertexDeclaration = new VertexDeclaration
    (
        new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
        new VertexElement(12, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0),
        new VertexElement(24, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)
    );

    VertexDeclaration IVertexType.VertexDeclaration
    {
        get { return VertexPositionNormal.VertexDeclaration; }
    }

}

A simple call to the class to initialise it. The Draw method is called in the master draw method in the Gamecomponent.

My current thoughts on this are:

  1. The direction of the weapon hitting the ship is used to get the middle position for the texture
  2. Wrap a texture around the drawn sphere based on this point of contact

Problem is i'm not sure how to do this. Can anyone help or if you have a better idea please tell me i'm open for opinion? :-) Thanks.

© Game Development or respective owner

Related posts about XNA

Related posts about c#