Sphere/Cylinder mapping with OpenGL

Started by
2 comments, last by blueshogun96 11 years ago
Hi All
I need spherical/cylindrical map for arbitrary objects (not a reflection mapping). Actually I'm calculating UV manually. If a polygon crosses UV seam or pole, then I split it into several new polygons. It works but it's a big piece of code that makes app much slower. Are there better ways with OpenGL?
Thanks
Tom
Advertisement

Tbh, I don't know the exact algorithms used to do this, but I have managed to do this (at least the spherical) in OpenGL by copying some code from the DirectX 9 SDK (the older ones) and changing the necessary features to work for OpenGL. It's been years since I've done this so I can't remember exactly what I changed for the sphere, but it should be obvious enough IMO.

Here's the sphere:


// Establish constants used in sphere generation
    DWORD dwNumSphereRings    = m_bHighTesselation ? 15 :  5;
    DWORD dwNumSphereSegments = m_bHighTesselation ? 30 : 10;
    FLOAT fDeltaRingAngle = ( D3DX_PI / dwNumSphereRings );
    FLOAT fDeltaSegAngle  = ( 2.0f * D3DX_PI / dwNumSphereSegments );

    D3DXVECTOR4 vT;
    FLOAT fScale;

    // Generate the group of rings for the sphere
    for( DWORD ring = 0; ring < (dwNumSphereRings/2); ring++ )
    {
        FLOAT r0 = sinf( (ring+0) * fDeltaRingAngle );
        FLOAT r1 = sinf( (ring+1) * fDeltaRingAngle );
        FLOAT y0 = cosf( (ring+0) * fDeltaRingAngle );
        FLOAT y1 = cosf( (ring+1) * fDeltaRingAngle );

        // Generate the group of segments for the current ring
        for( DWORD seg = 0; seg < (dwNumSphereSegments+1); seg++ )
        {
            FLOAT x0 =  r0 * sinf( seg * fDeltaSegAngle );
            FLOAT z0 =  r0 * cosf( seg * fDeltaSegAngle );
            FLOAT x1 =  r1 * sinf( seg * fDeltaSegAngle );
            FLOAT z1 =  r1 * cosf( seg * fDeltaSegAngle );

            // Add two vertices to the strip which makes up the sphere
            // (using the transformed normal to generate texture coords)
            (*vtx).p   = (*vtx).n   = D3DXVECTOR3(x0,y0,z0);
            D3DXVec3Transform( &vT, &(*vtx).n, &matWorldView );
            fScale = 1.37f / D3DXVec4Length( &vT );
            (*vtx).tu1 = 0.5f + fScale*vT.x;
            (*vtx).tv1 = 0.5f - fScale*vT.y;
            vtx++;

            (*vtx).p   = (*vtx).n   = D3DXVECTOR3(x1,y1,z1);
            D3DXVec3Transform( &vT, &(*vtx).n, &matWorldView );
            fScale = 1.37f / D3DXVec4Length( &vT );
            (*vtx).tu1 = 0.5f + fScale*vT.x;
            (*vtx).tv1 = 0.5f - fScale*vT.y;
            vtx++;
        }
    }

Then draw as a triangle strip. You'll have to use your own matrix transformation and vector length functions to do the texture coordinates, but that shouldn't be hard.

The cylinder is much easier. I don't know if you want an open or closed cylinder, I've never done the latter.


for( DWORD i=0; i<50; i++ )
    {
        FLOAT theta = (2*D3DX_PI*i)/(50-1);

        pVertices[2*i+0].position = D3DXVECTOR3( sinf(theta),-1.0f, cosf(theta) );
        pVertices[2*i+0].color    = 0xffffffff;
        pVertices[2*i+0].tu       = ((FLOAT)i)/(50-1);
        pVertices[2*i+0].tv       = 1.0f;

        pVertices[2*i+1].position = D3DXVECTOR3( sinf(theta), 1.0f, cosf(theta) );
        pVertices[2*i+1].color    = 0xff808080;
        pVertices[2*i+1].tu       = ((FLOAT)i)/(50-1);
        pVertices[2*i+1].tv       = 0.0f;
    }

Then draw as a triangle strip. This example uses 100 vertices btw.

Not sure if this helped, but I tried. smile.png

Shogun.

blueshougun96. thx for your reply. I've no problems with UV calculation itself, my question was about "should I do that" or, in other words. "can I avoid manual UV calcs?". An answer "no, you can't" would be also informative for me, if so I'm doing things right

Thanks

Tom

Okay, my mistake.

Generally speaking, it should be fine, that's what I'd do. I don't know of any way to do it automatically, unless OpenGL has an equivalent of D3DTSS_TCI_x.

Shogun

This topic is closed to new replies.

Advertisement