Generating Spheres

Started by
3 comments, last by SIGMA 22 years, 2 months ago
Hello, Okay here''s the situation: I need to algorthimically generate the verticies for a sphere composed of triangles with a radius of ''r'' and possibly a scalable level of detail. Does anyone know how to do this? Thanks, -Jesse
Advertisement
Well, if you start with vertices (0, -2*sqrt(2), -1), (-sqrt(6), sqrt(2), -1), (sqrt(6), sqrt(2), -1) and (0, 0, 3) then you can combine those into four equilateral triangles that will each share edges with each of the other three. They will just fit in a sphere of radius 3 centered at the origin. You can divide each face into 4 more triangles by connecting the midpoints of the edges. You can then push each of these new vertices out to the radius of a circle. They are all the same distance from the origin and if you view them as vectors then you are scaling them by equal amounts. The triangles formed by your new vertices will be equilateral triangles, but the ones formed using one of your old vertices and two of your new vertices will not be. Your new vertices are roughly 1.5 times as far way from each other as they are from the original vertices.
Keys to success: Ability, ambition and opportunity.
Okay, that makes sense, I was thinking about having an angle offset and casting a ray with length ''r'' out at increments on one plane equale to the offset, rotating the plane a few degrees and repeat. Kind of like stacking cross sections together...
-Jesse
Sorry, I thought you meant something like a geodesic dome, but with triangles. The parametric equation for a sphere is r(s,t)=(r*cos(s)*sin(t)+cx, r*sin(s)*sin(t)+cy, r*cos(t)+cz) where s ranges from 0 to 2*pi and t ranges from 0 to pi. That will give you a sphere with radius r centered at (cx,cy,cz). I think the easiest way to build the mesh is to do one latitude line at a time. For each latitude line you do every other longitude line and you alternate between latitude lines. What I mean by that is if you numbered the longitude lines and latitude lines then perhaps on even latitude line you generate points at even longitude lines and on odd latitude lines you generate points at odd longitude lines. The poles are triangle fans so you have the pole followed by what would be the odd entries in a triangle strip. Those are also what will be the even entries in the triangle strip between the first and second latitude lines so you insert them where they go as you build the cap. When you complete a revolution you have the cap and half the first latitude strip. The you do the second latitude line, use it to finish the first latitude strip and build half the next latitude strip. When you get to the last latitude strip the pole has to be the first entry in the triangle fan for the other cap.

Performance wise it is best to not have conditionals in the middle of a loop so it would be best to build one cap before you enter the loop and the other cap after you exit the loop. When you enter the loop the cap has built half the first longitude strip and when you exit only half of the last latitude strip has been built so the cap at the end has to finish it off. Also do two latitude lines per pass. That way you don''t have to check whether this one is even or odd because you always start the loop on an even or odd latitude line. It should make your logic a bit easier to get right since you don''t have to worry about conditionals. Your last vertices on a latitude strip is your first one so you can just copy it after you finish the rest of the strip. Since each vertices along a latitude line is a fixed angular increment from the previous one you could speed things up by calculating the sin and cos of the increment and using the angle addition formulas for sin and cos to rotate the point around a coordinate axis. You have several angles though. There is the increment from latitude to latitude, longitude to longitude and twice the increment from longitude to longitude. That last one is the one you use most since you only do every other longitude line on a given latitude line, but every other latitude line starts at the second longitude line instead of the first. That offset will keep you from being able to directly use a rotation around a coordinate axis to get the start of each latitude line. Using the angle addition formulas to rotate a point around the z axis is x''=x*cos(dt)-y*sin(dt), y''=x*sin(dt)+cos(dt) and z is not changed. You would of course have to generate your sphere centered at the origin and then translate it to where you want it after generating a point.
Keys to success: Ability, ambition and opportunity.
Whew, I got it to work. ( about time ) I found someone's code on the 'net that generated spheres, but it just wasn't working correctly, but after about a while of tweaking it, I got it.
Thanks for that lenghty post LilBudyWizer, it helped a lot!
Most of this code came from Microsoft, so it's most likely horribly flawed, but here it is nonetheless...
    // Establish constants used in sphere generation    DWORD dwNumSphereRings    = m_bHighTesselation ? 15 :  5;    DWORD dwNumSphereSegments = m_bHighTesselation ? 30 : 10;    FLOAT fDeltaRingAngle = ( PI / dwNumSphereRings );    FLOAT fDeltaSegAngle  = ( 2.0f * PI / dwNumSphereSegments );    D3DXVECTOR4 vT;    FLOAT fScale;    // Generate the group of rings for the sphere    for( DWORD ring = 0; ring < dwNumSphereRings; 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 = D3DXVECTOR3(x0,y0,z0);            (*vtx).tu1 = -((FLOAT)seg)/dwNumSphereSegments;            (*vtx).tv1 =(ring+0)/(FLOAT)dwNumSphereRings;            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 = D3DXVECTOR3(x1,y1,z1);            (*vtx).tu1 = -((FLOAT)seg)/dwNumSphereSegments;            (*vtx).tv1 = (ring+1)/(FLOAT)dwNumSphereRings;            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++;        }    }  

-Jesse

Edited by - SIGMA on February 3, 2002 2:23:46 PM

This topic is closed to new replies.

Advertisement