We can even add textures to our 3D plots (the goal here is to show how the texture coordinates would be arranged for such a thing): The explanation is in the comments - we take the interpolation functions - one for the texture value at a percent (goes from 0 to 1, hence the simple Vf = Percent) and another for the initial value (goes from -3 to +3)... from there I get the easy formula.
        'After that workout, we now have to actually set the vertices.
        'We do this by locking the surface out of D9 while we "operate" on it.
        Dim A As Array = vxbf.Lock(0, LockFlags.None)
        'It returns a vanilla array...
        vs = DirectCast(A, CustomVertex.PositionNormalTextured())
        'So we have to convert it to an array of the appropriate vertices.

        'Z = F(X, Y), but this time with texture.
        'Our texture should be 0,0 at X,Y = -3,-3 and 1,1 at X,Y = 3,3
        'So, we will simply do an interpolation during this process.
        'An interpolation is, again, like this:
        'Vf = L + Percent * (H - L), where Vf is the texture value, L is the lowest texture value, and H is the highest texture value.
        'Percent would also be an interpolation: Percent = (Vo - L) / (H - L)
        'where Vo is the loop variable value, L is the lowest loop value, and H is the highest loop value.
        'The first formula would be Vf = 0 + Percent * (1 - 0) = Percent.
        'The second formula would be Percent = (Vo - -3) / (3 - -3) = (Vo + 3) / 6,
        'Therefore, Vf = (Vo + 3) / 6
        'with L + dL
        'Vf = (Vo + dVo + 3) / 6


        For LY = -3.0F To 2.999F Step 0.25F
            For LX = -3.0F To 2.999F Step 0.25F
                'triangle 1:
                vs(Ctr) = New CustomVertex.PositionNormalTextured(LX, LY, F(LX, LY), 0.0F, 0.0F, 0.0F, (LX + 3.0F) / 6.0F, (LY + 3.0F) / 6.0F)
                vs(Ctr + 1) = New CustomVertex.PositionNormalTextured(LX + 0.25F, LY, F(LX + 0.25F, LY), 0.0F, 0.0F, 0.0F, (LX + 3.25F) / 6.0F, (LY + 3.0F) / 6.0F)
                vs(Ctr + 2) = New CustomVertex.PositionNormalTextured(LX, LY + 0.25F, F(LX, LY + 0.25F), 0.0F, 0.0F, 0.0F, (LX + 3.0F) / 6.0F, (LY + 3.25F) / 6.0F)
                'triangle 2:
                vs(Ctr + 3) = New CustomVertex.PositionNormalTextured(LX + 0.25F, LY + 0.25F, F(LX + 0.25F, LY + 0.25F), 0.0F, 0.0F, 0.0F, (LX + 3.25F) / 6.0F, (LY + 3.25F) / 6.0F)
                vs(Ctr + 4) = vs(Ctr + 2)
                vs(Ctr + 5) = vs(Ctr + 1)
                Ctr += 6
            Next
        Next
We also have to state the proper number of vertices: it's 3456, remember?
            VertexCount = 3456
            PrT = PrimitiveType.TriangleList
            VxB = New VertexBuffer(GetType(CustomVertex.PositionNormalTextured), VertexCount, D9, Usage.WriteOnly, CustomVertex.PositionNormalTextured.Format, Pool.Managed)
            'That is a LOT of non-trivial parameters.
We also need to recalibrate our light location.
        D9.Lights(0).Position = New Vector3(0.0F, 0.0F, 2.0F) 'Place the bulb here.
        D9.Lights(0).Range = 4.8F
        D9.Lights(0).Attenuation0 = 0.0F
        D9.Lights(0).Attenuation1 = 0.95F
        'Has to be just right... if it is too low, you'll have darkness... if it is
        'too high, you'll have a overly lit object.
After making a few slight changes, you can make the same picture that I made on the main page!
.vb file