2
\$\begingroup\$

[this question is somewhat long. here's my question in a nutshell]

I want to use multiple types of Vertex data types for my triangle, interchangeably. So if I have a generic type T

private void AddTriangle<T> (Vector3[] positions, Color[] colors = null, Texture2D texture = null)

And I identify T...

if(typeof(T) = typeof(VertexPositionColor){ ... }
if(typeof(T) = typeof(VertexPositionTexture){ ... }

How can I use T as if it actually is a VertexPositionColor or VertexPositionTexture? [/nutshell]

So in terms of types of vertices in C#/XNA, there's VertexPositionColor...

Then VertexPositionTexture, and VertexPositionNormalTexture, and VertexPositionColorTexture...

I'm trying to set up a system where I can create 3D worlds without much of a limit - I don't like limits. Nobody does, if I had to take a guess. My problem is that my methods, as well as lists, and rendering code all use "VertexPositionColor" hardcoded into the program. Even my triangle rotation method explicitly has "VertexPositionColor" typed in there. So suppose I had a list of VertexPositionTexture vertices that I wanted to use to render a model, in addition to all of the VertexPositionColor vertices used for other purposes. Is there a way I can easily switch between the four different types of triangles, without having to rewrite all of my methods and code hardcoded for each triangle type? (I'm not sure if generics would work here - it turned into a mess of type-casting, and I'm not sure if it's possible to restrict types)

Another question - how useful are the options? Within usual game development, is there ever really a use for VertexPositionColor vertices rather than VertexPositionTexture or VertexPositionColorTexture? Or is there a vertex type that is more versatile than the others?

EDIT: as requested, here's some of the code that has the VertexPositionColor hardcoded into it. I'd like to make the following code work for all vertex types, if possible:

    private void RotateTriangles(long TriangleID1, long TriangleID2, Vector3 AroundPoint, Vector3 Rotation, string Key)
    {
        float Sine1, Cosine1, Sine2, Cosine2, Sine3, Cosine3;
        Sine1 = (float)Math.Sin(MathHelper.ToRadians(Rotation.X));
        Cosine1 = (float)Math.Cos(MathHelper.ToRadians(Rotation.X));
        Sine2 = (float)Math.Sin(MathHelper.ToRadians(Rotation.Y));
        Cosine2 = (float)Math.Cos(MathHelper.ToRadians(Rotation.Y));
        Sine3 = (float)Math.Sin(MathHelper.ToRadians(Rotation.Z));
        Cosine3 = (float)Math.Cos(MathHelper.ToRadians(Rotation.Z));
        long TriI = TriangleID1;
        long point;
        float tmp;
        VertexPositionColor[] vertices = triangleData[Key].ToArray();
        while (TriI <= TriangleID2)
        {
            point = 0;
            while (point < 3)
            {
                tmp = vertices[TriI * 3 + point].Position.Z;
                vertices[TriI * 3 + point].Position.Z = AroundPoint.Z + ((vertices[TriI * 3 + point].Position.Z - AroundPoint.Z) * Cosine1) - ((vertices[TriI * 3 + point].Position.Y - AroundPoint.Y) * Sine1);
                vertices[TriI * 3 + point].Position.Y = AroundPoint.Y + ((tmp - AroundPoint.Z) * Sine1) + ((vertices[TriI * 3 + point].Position.Y - AroundPoint.Y) * Cosine1);

                tmp = vertices[TriI * 3 + point].Position.X;
                vertices[TriI * 3 + point].Position.X = AroundPoint.X + ((vertices[TriI * 3 + point].Position.X - AroundPoint.X) * Cosine2) - ((vertices[TriI * 3 + point].Position.Z - AroundPoint.Z) * Sine2);
                vertices[TriI * 3 + point].Position.Z = AroundPoint.Z + ((tmp - AroundPoint.X) * Sine2) + ((vertices[TriI * 3 + point].Position.Z - AroundPoint.Z) * Cosine2);

                tmp = vertices[TriI * 3 + point].Position.X;
                vertices[TriI * 3 + point].Position.X = AroundPoint.X + ((vertices[TriI * 3 + point].Position.X - AroundPoint.X) * Cosine3) - ((vertices[TriI * 3 + point].Position.Y - AroundPoint.Y) * Sine3);
                vertices[TriI * 3 + point].Position.Y = AroundPoint.Y + ((tmp - AroundPoint.X) * Sine3) + ((vertices[TriI * 3 + point].Position.Y - AroundPoint.Y) * Cosine3);


                point++;
            }
            TriI++;
        }
        triangleData[Key] = vertices.ToList();
    }
    private void AddArrayToDictionary(string Key, VertexPositionColor[] array, int[] vertices = null)
    {
        List<VertexPositionColor> fixedlist = array.ToList();

        if (!triangleData.ContainsKey(Key))
        {
            triangleData.Add(Key, new List<VertexPositionColor>());
        }
        triangleData[Key].AddRange(fixedlist);

        if (vertices != null)
        {
            List<int> indexdata = vertices.ToList();
            if (!indicesData.ContainsKey(Key))
            {
                indicesData.Add(Key, new List<int>);
            }
            indicesData[Key].AddRange(indexdata);
        }
    }
    private void AddTriangle(Vector3[] vertices, Color[] colours, string Key, bool Indices_On)
    {
        if (!triangleData.ContainsKey(Key))
        {
            triangleData.Add(Key, new List<VertexPositionColor>());
        }
        for (int i = 0; i < vertices.Count(); i++)
        {
            VertexPositionColor check = new VertexPositionColor(vertices[i], colours[i]);
            if(!triangleData[Key].Contains(check) || !Indices_On)
            {
                triangleData[Key].Add(check);
            }
        }
    }

And here's the structure I'm using for my triangle vertices:

    Dictionary<string, List<VertexPositionColor>> triangleData = new Dictionary<string, List<VertexPositionColor>>();
    Dictionary<string, List<int>> indicesData = new Dictionary<string, List<int>>();

And finally, here's my draw code:

    protected override void Draw(GameTime gameTime)
    {
        RasterizerState rs = new RasterizerState();
        rs.CullMode = CullMode.None;
        rs.FillMode = FillMode.WireFrame;
        device.RasterizerState = rs;
        device.Clear(Color.DarkSlateBlue);
        effects.CurrentTechnique = effects.Techniques["ColoredNoShading"];
        effects.Parameters["xView"].SetValue(Game_Camera.view);
        effects.Parameters["xProjection"].SetValue(Game_Camera.projection);
        effects.Parameters["xWorld"].SetValue(Matrix.Identity);
        foreach (EffectPass fxpass in effects.CurrentTechnique.Passes)
        {
            fxpass.Apply();
            device.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, triangleData["Landscape"].ToArray(), 0, 5, indicesData["Landscape"].ToArray(), 0, 2, VertexPositionColor.VertexDeclaration);
        }

        base.Draw(gameTime);
    }
\$\endgroup\$
  • \$\begingroup\$ > Even my triangle rotation method explicitly has "VertexPositionColor" typed in there Why? This sounds like an X/Y problem. Vertex types are only used when you need to draw a primitive. Everything else should be agnostic to the vertex type. \$\endgroup\$ – mklingen Feb 23 '15 at 22:33
  • \$\begingroup\$ I don't mean my camera rotation, I mean a rotation method that actually changes the data of my triangles. Which means changing the data of my VertexPositionColor items. \$\endgroup\$ – Superdoggy Feb 23 '15 at 23:01
  • \$\begingroup\$ Why are you changing the data? You say you are doing "triangle rotation". What does this mean? Typically, you have vertex buffers (which can have arbitrary vertex types), and you do operations on those vertex buffers. No code except the code that fills vertex buffers needs to know about the triangle type. \$\endgroup\$ – mklingen Feb 23 '15 at 23:21
  • \$\begingroup\$ It's so that I can manipulate the rotation of individual triangles during gameplay. Since my triangles are defined via large dictionary filled with lists of VertexPositionColor items, I can manipulate each triangle individually at my own will with little effort whenever I want to. My only problem with this method is that it makes it hard to switch between triangle types. \$\endgroup\$ – Superdoggy Feb 24 '15 at 0:26
  • \$\begingroup\$ Okay, can you post some of this code? Having a hard time grasping why you'd do it this way. \$\endgroup\$ – mklingen Feb 24 '15 at 1:16
3
\$\begingroup\$

This question seems to be an X/Y problem. I think what you are really asking "how do I rotate a set of triangles?" You've settled on a very slow, very wrong solution to this problem. You should never be directly modifying vertex data on the CPU, unless you absolutely have to. I think your answer boils down to replacing:

effects.Parameters["xWorld"].SetValue(Matrix.Identity);

With:

effects.Parameters["xWorld"].SetValue(RotationMatrix);

Where

RotationMatrix = Matrix.CreateRotationX(Rotation.X) * 
    Matrix.CreateRotationY(Rotation.Y) * 
    Matrix.CreateRotationZ(Rotation.Z) *
    Matrix.CreateTranslation(AroundPoint);

Also, to answer your original question, generics can work. All thats needed is a guarantee that the type T contains the element Position. You can force T to be of a particular type or interface in this way:

public void FunctionName<T>(...) where T : OtherType

That said, the best way to get around this is to not store the vertex structs directly if you're going to generate/operate on them. Instead, convert from the raw data. Do this:

Dictionary<string, List<Vector3>> positions = new Dictionary<string, List<Vector3>>();\
Dictionary<string, List<Color>> colors = new Dictionary<string, List<Color>>();
Dictionary<string, List<Vector>> uvs = new Dictionary<string, List<Vector2>>();
Dictionary<string, List<int>> indices = new Dictionary<string, List<int>>();

Or better yet, make a class for a Mesh that contains all of these:

class Mesh
{
    public List<Vector3> positions;
    public List<Color> colors;
    public List<Vector2> uvs;
    public List<int> indices;
    public VertexBuffer buffer;
}

Then, when you populate the vertex buffer, interpret the type based on an enum, or just the presence/absence of each of these fields.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.