3

In C#.net I have a mesh cylinder with a dynamic diameter and length and am trying to map a texture to it. I have spent the better part of a day trying to find out how to do so but have had no success finding any information on Google.

The cylinders texture has a top area of the jpg and the side has the rest of the jpg. I need to position the jpgs image edge along the top edge of the cylinder. eg. Red on top and green on side using one image.

Can anyone help me to map the VertexBuffer points to the texture?

C#.Net 2008 DirectX 9 (unmanaged)

I Have Posted My Working Solution Below

Craig White
  • 13,492
  • 4
  • 23
  • 36
  • Just calculate the texture coordinates. This looks straight-forward. What is the exact problem you are having? Can you post some of your failed results? – Stephen Chung Apr 07 '11 at 09:08
  • I have figured it out now. The problem is that I suck at maths and was generating the Mesh automatically using DirectX so I had no-idea how the mesh was created or layed out ;) I have posted my new working code below in an answer. – Craig White Apr 08 '11 at 01:55
  • that's the spirit! You really need to brush up on your math if you want to do graphics programming -- there is just no way around it. – Stephen Chung Apr 08 '11 at 03:12

2 Answers2

1

Although this tutorial is in VB it clearly explains the process.

Calculating the texture coordinates can be quite some work; that is why normally this is done by 3D modeling software so you can easily and, more importantly, visually adjust the mapping.

Let me know if you have any questions.

EDIT

For adding texture coordinates to the DirecxtX generated cylinder see this

Emond
  • 50,210
  • 11
  • 84
  • 115
  • BTW: what do you mean by unmanaged DirectX? Did you create your own wrapper or are you using a library such as SlimDX? – Emond Apr 07 '11 at 06:55
  • Hmmm... This tutorial refers to attaching a texture to a hollow cylinder. My cylinder has a top and bottom. I am using `Microsoft.DirectX.Direct3D.Mesh.Cylinder` to create it. Unmanaged is reffering to that we are using the original DirectX libraries and not the .Net Managed version. – Craig White Apr 07 '11 at 06:57
  • I added another link that might help you with the Microsoft.DirectX.Direct3D.Mesh.Cylinder. So how are you wrapping the unmanaged libraries, PInvoke? – Emond Apr 07 '11 at 07:02
  • I am not sure how we are doing it, the project has been going since 2004. I have only started working on the project recently creating a different module of the project and am implementing 3D models into the display.(There is another comment after this one, press show more to see it) – Craig White Apr 07 '11 at 07:13
  • The additional article you sent me, I have seen many times today but have not had any luck with it. It simply just displays a solid gray outline of the cylinder. – Craig White Apr 07 '11 at 07:14
  • I am sorry but that is pretty hard to give any advice on without having code to look at. Could you use the code of the article to see if that works on your machine and then slowly turn it into the setup in your application? It can be anything from lighting to false UV coordinates or an incompatible bitmap. – Emond Apr 07 '11 at 07:18
  • I've copied the settings exactly to no avail. Anyway, I did a test run on the code in that example. The image was radiating away from the sides. – Craig White Apr 07 '11 at 07:52
  • Hmmm, 'radiating away' what does that mean? – Emond Apr 07 '11 at 08:11
  • all the image is warped to pointing at a location on the side of the cylinder. Im needing to display it like when you make a paper cylinder at school, rectangle bent into a cylinder with a flap on top and bottom. – Craig White Apr 07 '11 at 22:12
  • Apparently they use a spherical mapping ( http://www.mvps.org/directx/articles/spheremap.htm ). What you are asking for is a cylindrical mapping ( http://www.helixsoft.nl/articles/sphere/sphere.html#cylinder ). The texturemap that you need has to circles and a rectangle mapped to the cylinder. So you have to calculate two circles and a rectangle in UV space at the point where your cylinder has vertices. – Emond Apr 08 '11 at 04:22
1

Ok, I've finally figured it out. I had some code previously that was working but not exactly what I was wanting from http://channel9.msdn.com/coding4fun/articles/Ask-the-ZMan-Applying-Textures-Part-3

Anyway, I just did some mods to it.

For reference and for those arriving from Google, here you go.

public static float ComputeBoundingSphere(Mesh mesh, out Microsoft.DirectX.Vector3 center)
    {
        // Lock the vertex buffer
        Microsoft.DirectX.GraphicsStream data = null;
        try
        {
            data = mesh.LockVertexBuffer(LockFlags.ReadOnly);
            // Now compute the bounding sphere
            return Geometry.ComputeBoundingSphere(data, mesh.NumberVertices, 
                mesh.VertexFormat, out center);
        }
        finally
        {
            // Make sure to unlock the vertex buffer
            if (data != null)
                mesh.UnlockVertexBuffer();
        }
    }

    private static Mesh SetSphericalTexture(Mesh mesh)
    {
        Microsoft.DirectX.Vector3 vertexRay;
        Microsoft.DirectX.Vector3 meshCenter;
        double phi;
        float u;


        Microsoft.DirectX.Vector3 north = new Microsoft.DirectX.Vector3(0f, 0f, 1f);
        Microsoft.DirectX.Vector3 equator = new Microsoft.DirectX.Vector3(0f, 1f, 0f);
        Microsoft.DirectX.Vector3 northEquatorCross = Microsoft.DirectX.Vector3.Cross(north, equator);

        ComputeBoundingSphere(mesh, out meshCenter);

        using (VertexBuffer vb = mesh.VertexBuffer)
        {
            CustomVertex.PositionNormalTextured[] verts = (CustomVertex.PositionNormalTextured[])vb.Lock(0, typeof(CustomVertex.PositionNormalTextured), LockFlags.None, mesh.NumberVertices);
            try
            {
                for (int i = 0; i < verts.Length; i++)
                {
                    //For each vertex take a ray from the centre of the mesh to the vertex and normalize so the dot products work.
                    vertexRay = Microsoft.DirectX.Vector3.Normalize(verts[i].Position - meshCenter);

                    phi = Math.Acos((double)vertexRay.Z);
                    if (vertexRay.Z > -0.9)
                    {
                        verts[i].Tv = 0.121f; //percentage of the image being the top side
                    }
                    else
                        verts[i].Tv = (float)(phi / Math.PI);

                    if (vertexRay.Z == 1.0f || vertexRay.Z == -1.0f)
                    {
                        verts[i].Tu = 0.5f;
                    }
                    else
                    {
                        u = (float)(Math.Acos(Math.Max(Math.Min((double)vertexRay.Y / Math.Sin(phi), 1.0), -1.0)) / (2.0 * Math.PI));
                        //Since the cross product is just giving us (1,0,0) i.e. the xaxis 
                        //and the dot product was giving us a +ve or -ve angle, we can just compare the x value with 0
                        verts[i].Tu = (vertexRay.X > 0f) ? u : 1 - u;
                    }
                }
            }
            finally
            {
                vb.Unlock();
            }
        }
        return mesh;
    }
Craig White
  • 13,492
  • 4
  • 23
  • 36