Sign in to follow this  
Upinflames

3D Sphere Texturing

Recommended Posts

Hello, I am doing a project that makes a 3D Earth that rotates. I have it all completed except the texture rendering differently. I am following ZMans tutorial on Coding4Fun. I am using C# and Managed DirectX. Here is my texturing procedure and my mesh creating procedure:
        private void LoadMesh()
        {
            ExtendedMaterial[] materialarray;
            sphere = Mesh.FromFile(System.Windows.Forms.Application.StartupPath + @"\..\..\bin\Release\Sphere.x", MeshFlags.Managed, device, out materialarray);

            if ((materialarray != null) && (materialarray.Length > 0))
            {
                m_materials = new Material[materialarray.Length];

                for (int i = 0; i < materialarray.Length; i++)
                {
                    m_materials[i] = materialarray[i].Material3D;
                    m_materials[i].Ambient = m_materials[i].Diffuse;
                }
            }


            sphere = sphere.Clone(sphere.Options.Value, CustomVertex.PositionNormalTextured.Format, device);
            sphere = SetSphericalTexture(sphere.Clone(sphere.Options.Value, sphere.VertexFormat | VertexFormats.Texture0, sphere.Device));
            //sphere.ComputeNormals();
            
            VertexBuffer vertices = sphere.VertexBuffer;
            GraphicsStream stream = vertices.Lock(0, 0, LockFlags.None);
            Vector3 meshcenter;
            meshradius = Geometry.ComputeBoundingSphere(stream, sphere.NumberVertices, sphere.VertexFormat, out meshcenter);
            vertices.Unlock();
        }
        private static Mesh SetSphericalTexture(Mesh mesh)
        {
            Vector3 vertexRay;
            Vector3 meshCenter;
            double phi;
            float u;

            Vector3 north = new Vector3(0f, 0f,1f);
            Vector3 equator = new Vector3(0f, 1f, 0f);
            Vector3 northEquatorCross = 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 = Vector3.Normalize(verts[i].Position - meshCenter);

                        ////Ref:http://www.cs.unc.edu/~rademach/xroads-RT/RTarticle.html and
                        ////Glassner, A. (ed) An Introduction to Ray Tracing. Academic Press New York, N.Y. 1989. 
                        //phi = Math.Acos((double)Vector3.Dot(north, vertexRay));
                        //verts[i].Tv = (float)(phi / Math.PI);
                        //if (phi == 0.0) //if north and vertex ray are coincident then we can pick an arbitray u since its the entire top/bottom line of the texture
                        //{
                        //    u = 0.5f;
                        //}
                        //else
                        //{
                        //    //Clamp the acos() param to 1.0/-1.0 (rounding errors are sometimes taking it slightly over.
                        //    u = (float)(Math.Acos(Math.Max(Math.Min((double)Vector3.Dot(equator, vertexRay) / Math.Sin(phi), 1.0), -1.0)) / (2.0 * Math.PI));
                        //    if (Vector3.Dot(northEquatorCross, vertexRay) < 0.0)
                        //    {
                        //        verts[i].Tu = u;
                        //    }
                        //    else
                        //    {
                        //        verts[i].Tu = 1 - u;
                        //    }
                        //}

                        //Since we know we are using normalised axis we can simplify this somewhat!
                        //Note these simplifcations only apply if the basis vectors are the unit axis
                        //north=(0,0,1)=zaxis, equator=(0,1,0)=yaxis and north x equator=(1,0,0)=xaxis
                        //since (0,0,1)dot(x,y,z)==z and (0,1,0)dot(x,y,z)==y

                        //if north and vertex ray are coincident then we can pick an arbitray u since its the entire top/bottom line of the texture
                        phi = Math.Acos((double)vertexRay.Z);
                        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;
        }
        public static float ComputeBoundingSphere(Mesh mesh, out Vector3 center)
        {

            // Lock the vertex buffer
            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 void DrawMesh(Mesh mesh, Material[] meshmaterials)
        {
            for (int i = 0; i < meshmaterials.Length; i++)
            {
                device.Material = meshmaterials[i];
                mesh.DrawSubset(i);
            }
        }
Here is a picture of what it looks like when it renders: Free Image Hosting at www.ImageShack.us (Ignore the reness of it, I want it to be red.) If someone could help me that would be appreciated because I have been attempting to resolve it with no success. [Edited by - Upinflames on September 20, 2008 12:20:26 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this