Example #1
0
//----------------------------------------------------------------------------
TriMesh* StandardMesh::Sphere (int zSamples, int radialSamples,
    float radius)
{
    int zsm1 = zSamples-1, zsm2 = zSamples-2, zsm3 = zSamples-3;
    int rsp1 = radialSamples+1;
    int numVertices = zsm2*rsp1 + 2;
    int numTriangles = 2*zsm2*radialSamples;
    int numIndices = 3*numTriangles;
    int stride = mVFormat->GetStride();

    // Create a vertex buffer.
    VertexBuffer* vbuffer = new0 VertexBuffer(numVertices, stride, mUsage);
    VertexBufferAccessor vba(mVFormat, vbuffer);

    // Generate geometry.
    float invRS = 1.0f/(float)radialSamples;
    float zFactor = 2.0f/(float)zsm1;
    int r, z, zStart, i, unit;
    Float2 tcoord;

    // Generate points on the unit circle to be used in computing the mesh
    // points on a cylinder slice.
    float* sn = new1<float>(rsp1);
    float* cs = new1<float>(rsp1);
    for (r = 0; r < radialSamples; ++r)
    {
        float angle = Mathf::TWO_PI*invRS*r;
        cs[r] = Mathf::Cos(angle);
        sn[r] = Mathf::Sin(angle);
    }
    sn[radialSamples] = sn[0];
    cs[radialSamples] = cs[0];

    // Generate the cylinder itself.
    for (z = 1, i = 0; z < zsm1; ++z)
    {
        float zFraction = -1.0f + zFactor*z;  // in (-1,1)
        float zValue = radius*zFraction;

        // Compute center of slice.
        APoint sliceCenter(0.0f, 0.0f, zValue);

        // Compute radius of slice.
        float sliceRadius = Mathf::Sqrt(Mathf::FAbs(
            radius*radius - zValue*zValue));

        // Compute slice vertices with duplication at endpoint.
        AVector normal;
        int save = i;
        for (r = 0; r < radialSamples; ++r)
        {
            float radialFraction = r*invRS;  // in [0,1)
            AVector radial(cs[r], sn[r], 0.0f);

            vba.Position<Float3>(i) = sliceCenter + sliceRadius*radial;

            if (mHasNormals)
            {
                normal = vba.Position<Float3>(i);
                normal.Normalize();
                if (mInside)
                {
                    vba.Normal<Float3>(i) = -normal;
                }
                else
                {
                    vba.Normal<Float3>(i) = normal;
                }
            }

            tcoord[0] = radialFraction;
            tcoord[1] = 0.5f*(zFraction + 1.0f);
            for (unit = 0; unit < MAX_UNITS; ++unit)
            {
                if (mHasTCoords[unit])
                {
                    vba.TCoord<Float2>(unit, i) = tcoord;
                }
            }

            ++i;
        }

        vba.Position<Float3>(i) = vba.Position<Float3>(save);
        if (mHasNormals)
        {
            vba.Normal<Float3>(i) = vba.Normal<Float3>(save);
        }

        tcoord[0] = 1.0f;
        tcoord[1] = 0.5f*(zFraction + 1.0f);
        for (unit = 0; unit < MAX_UNITS; ++unit)
        {
            if (mHasTCoords[unit])
            {
                vba.TCoord<Float2>(unit, i) = tcoord;
            }
        }

        ++i;
    }

    // south pole
    vba.Position<Float3>(i) = Float3(0.0f, 0.0f, -radius);
    if (mHasNormals)
    {
        if (mInside)
        {
            vba.Normal<Float3>(i) = Float3(0.0f, 0.0f, 1.0f);
        }
        else
        {
            vba.Normal<Float3>(i) = Float3(0.0f, 0.0f, -1.0f);
        }
    }

    tcoord = Float2(0.5f, 0.5f);
    for (unit = 0; unit < MAX_UNITS; ++unit)
    {
        if (mHasTCoords[unit])
        {
            vba.TCoord<Float2>(unit, i) = tcoord;
        }
    }

    ++i;

    // north pole
    vba.Position<Float3>(i) = Float3(0.0f, 0.0f, radius);
    if (mHasNormals)
    {
        if (mInside)
        {
            vba.Normal<Float3>(i) = Float3(0.0f, 0.0f, -1.0f);
        }
        else
        {
            vba.Normal<Float3>(i) = Float3(0.0f, 0.0f, 1.0f);
        }
    }

    tcoord = Float2(0.5f, 1.0f);
    for (unit = 0; unit < MAX_UNITS; ++unit)
    {
        if (mHasTCoords[unit])
        {
            vba.TCoord<Float2>(unit, i) = tcoord;
        }
    }

    ++i;

    TransformData(vba);

    // Generate indices.
    IndexBuffer* ibuffer = new0 IndexBuffer(numIndices, 4, mUsage);
    int* indices = (int*)ibuffer->GetData();
    for (z = 0, zStart = 0; z < zsm3; ++z)
    {
        int i0 = zStart;
        int i1 = i0 + 1;
        zStart += rsp1;
        int i2 = zStart;
        int i3 = i2 + 1;
        for (i = 0; i < radialSamples; ++i, indices += 6)
        {
            if (mInside)
            {
                indices[0] = i0++;
                indices[1] = i2;
                indices[2] = i1;
                indices[3] = i1++;
                indices[4] = i2++;
                indices[5] = i3++;
            }
            else  // inside view
            {
                indices[0] = i0++;
                indices[1] = i1;
                indices[2] = i2;
                indices[3] = i1++;
                indices[4] = i3++;
                indices[5] = i2++;
            }
        }
    }

    // south pole triangles
    int numVerticesM2 = numVertices - 2;
    for (i = 0; i < radialSamples; ++i, indices += 3)
    {
        if (mInside)
        {
            indices[0] = i;
            indices[1] = i + 1;
            indices[2] = numVerticesM2;
        }
        else
        {
            indices[0] = i;
            indices[1] = numVerticesM2;
            indices[2] = i + 1;
        }
    }

    // north pole triangles
    int numVerticesM1 = numVertices-1, offset = zsm3*rsp1;
    for (i = 0; i < radialSamples; ++i, indices += 3)
    {
        if (mInside)
        {
            indices[0] = i + offset;
            indices[1] = numVerticesM1;
            indices[2] = i + 1 + offset;
        }
        else
        {
            indices[0] = i + offset;
            indices[1] = i + 1 + offset;
            indices[2] = numVerticesM1;
        }
    }

    delete1(cs);
    delete1(sn);

    // The duplication of vertices at the seam cause the automatically
    // generated bounding volume to be slightly off center.  Reset the bound
    // to use the true information.
    TriMesh* mesh = new0 TriMesh(mVFormat, vbuffer, ibuffer);
    mesh->GetModelBound().SetCenter(APoint::ORIGIN);
    mesh->GetModelBound().SetRadius(radius);
    return mesh;
}
Example #2
0
//----------------------------------------------------------------------------
TriMesh* StandardMesh::Torus (int circleSamples, int radialSamples,
    float outerRadius, float innerRadius)
{
    int numVertices = (circleSamples+1)*(radialSamples+1);
    int numTriangles = 2*circleSamples*radialSamples;
    int numIndices = 3*numTriangles;
    int stride = mVFormat->GetStride();

    // Create a vertex buffer.
    VertexBuffer* vbuffer = new0 VertexBuffer(numVertices, stride, mUsage);
    VertexBufferAccessor vba(mVFormat, vbuffer);

    // Generate geometry.
    float invCS = 1.0f/(float)circleSamples;
    float invRS = 1.0f/(float)radialSamples;
    int c, r, i, unit;
    Float2 tcoord;

    // Generate the cylinder itself.
    for (c = 0, i = 0; c < circleSamples; ++c)
    {
        // Compute center point on torus circle at specified angle.
        float circleFraction = c*invCS;  // in [0,1)
        float theta = Mathf::TWO_PI*circleFraction;
        float cosTheta = Mathf::Cos(theta);
        float sinTheta = Mathf::Sin(theta);
        AVector radial(cosTheta, sinTheta, 0.0f);
        AVector torusMiddle = outerRadius*radial;

        // Compute slice vertices with duplication at endpoint.
        int save = i;
        for (r = 0; r < radialSamples; ++r)
        {
            float radialFraction = r*invRS;  // in [0,1)
            float phi = Mathf::TWO_PI*radialFraction;
            float cosPhi = Mathf::Cos(phi);
            float sinPhi = Mathf::Sin(phi);
            AVector normal = cosPhi*radial + sinPhi*AVector::UNIT_Z;
            vba.Position<Float3>(i) = torusMiddle + innerRadius*normal;
            if (mHasNormals)
            {
                if (mInside)
                {
                    vba.Normal<Float3>(i) = -normal;
                }
                else
                {
                    vba.Normal<Float3>(i) = normal;
                }
            }

            tcoord = Float2(radialFraction, circleFraction);
            for (unit = 0; unit < MAX_UNITS; ++unit)
            {
                if (mHasTCoords[unit])
                {
                    vba.TCoord<Float2>(unit, i) = tcoord;
                }
            }

            ++i;
        }

        vba.Position<Float3>(i) = vba.Position<Float3>(save);
        if (mHasNormals)
        {
            vba.Normal<Float3>(i) = vba.Normal<Float3>(save);
        }

        tcoord = Float2(1.0f, circleFraction);
        for (unit = 0; unit < MAX_UNITS; ++unit)
        {
            if (mHasTCoords[unit])
            {
                vba.TCoord<Float2>(unit, i) = tcoord;
            }
        }

        ++i;
    }

    // Duplicate the cylinder ends to form a torus.
    for (r = 0; r <= radialSamples; ++r, ++i)
    {
        vba.Position<Float3>(i) = vba.Position<Float3>(r);
        if (mHasNormals)
        {
            vba.Normal<Float3>(i) = vba.Normal<Float3>(r);
        }

        for (unit = 0; unit < MAX_UNITS; ++unit)
        {
            if (mHasTCoords[unit])
            {
                vba.TCoord<Float2>(unit, i) =
                    Float2(vba.TCoord<Float2>(unit, r)[0], 1.0f);
            }
        }
    }

    TransformData(vba);

    // Generate indices.
    IndexBuffer* ibuffer = new0 IndexBuffer(numIndices, 4, mUsage);
    int* indices = (int*)ibuffer->GetData();
    int cStart = 0;
    for (c = 0; c < circleSamples; ++c)
    {
        int i0 = cStart;
        int i1 = i0 + 1;
        cStart += radialSamples + 1;
        int i2 = cStart;
        int i3 = i2 + 1;
        for (i = 0; i < radialSamples; ++i, indices += 6)
        {
            if (mInside)
            {
                indices[0] = i0++;
                indices[1] = i1;
                indices[2] = i2;
                indices[3] = i1++;
                indices[4] = i3++;
                indices[5] = i2++;
            }
            else  // inside view
            {
                indices[0] = i0++;
                indices[1] = i2;
                indices[2] = i1;
                indices[3] = i1++;
                indices[4] = i2++;
                indices[5] = i3++;
            }
        }
    }

    // The duplication of vertices at the seam cause the automatically
    // generated bounding volume to be slightly off center.  Reset the bound
    // to use the true information.
    TriMesh* mesh = new0 TriMesh(mVFormat, vbuffer, ibuffer);
    mesh->GetModelBound().SetCenter(APoint::ORIGIN);
    mesh->GetModelBound().SetRadius(outerRadius);
    return mesh;
}
Example #3
0
//----------------------------------------------------------------------------
TriMesh* StandardMesh::Cylinder (int axisSamples, int radialSamples,
    float radius, float height, bool open)
{
    TriMesh* mesh;
    int unit;
    Float2 tcoord;

    if (open)
    {
        int numVertices = axisSamples*(radialSamples+1);
        int numTriangles = 2*(axisSamples-1)*radialSamples;
        int numIndices = 3*numTriangles;
        int stride = mVFormat->GetStride();

        // Create a vertex buffer.
        VertexBuffer* vbuffer = new0 VertexBuffer(numVertices, stride,
            mUsage);

        VertexBufferAccessor vba(mVFormat, vbuffer);

        // Generate geometry.
        float invRS = 1.0f/(float)radialSamples;
        float invASm1 = 1.0f/(float)(axisSamples-1);
        float halfHeight = 0.5f*height;
        int r, a, aStart, i;

        // Generate points on the unit circle to be used in computing the
        // mesh points on a cylinder slice.
        float* cs = new1<float>(radialSamples + 1);
        float* sn = new1<float>(radialSamples + 1);
        for (r = 0; r < radialSamples; ++r)
        {
            float angle = Mathf::TWO_PI*invRS*r;
            cs[r] = Mathf::Cos(angle);
            sn[r] = Mathf::Sin(angle);
        }
        cs[radialSamples] = cs[0];
        sn[radialSamples] = sn[0];

        // Generate the cylinder itself.
        for (a = 0, i = 0; a < axisSamples; ++a)
        {
            float axisFraction = a*invASm1;  // in [0,1]
            float z = -halfHeight + height*axisFraction;

            // Compute center of slice.
            APoint sliceCenter(0.0f, 0.0f, z);

            // Compute slice vertices with duplication at endpoint.
            int save = i;
            for (r = 0; r < radialSamples; ++r)
            {
                float radialFraction = r*invRS;  // in [0,1)
                AVector normal(cs[r], sn[r], 0.0f);

                vba.Position<Float3>(i) = sliceCenter + radius*normal;

                if (mHasNormals)
                {
                    if (mInside)
                    {
                        vba.Normal<Float3>(i) = -normal;
                    }
                    else
                    {
                        vba.Normal<Float3>(i) = normal;
                    }
                }

                tcoord = Float2(radialFraction, axisFraction);
                for (unit = 0; unit < MAX_UNITS; ++unit)
                {
                    if (mHasTCoords[unit])
                    {
                        vba.TCoord<Float2>(unit, i) = tcoord;
                    }
                }

                ++i;
            }

            vba.Position<Float3>(i) = vba.Position<Float3>(save);

            if (mHasNormals)
            {
                vba.Normal<Float3>(i) = vba.Normal<Float3>(save);
            }

            tcoord = Float2(1.0f, axisFraction);
            for (unit = 0; unit < MAX_UNITS; ++unit)
            {
                if (mHasTCoords[unit])
                {
                    vba.TCoord<Float2>(0, i) = tcoord;
                }
            }

            ++i;
        }
        TransformData(vba);

        // Generate indices.
        IndexBuffer* ibuffer = new0 IndexBuffer(numIndices, 4, mUsage);
        int* indices = (int*)ibuffer->GetData();
        for (a = 0, aStart = 0; a < axisSamples-1; ++a)
        {
            int i0 = aStart;
            int i1 = i0 + 1;
            aStart += radialSamples + 1;
            int i2 = aStart;
            int i3 = i2 + 1;
            for (i = 0; i < radialSamples; ++i, indices += 6)
            {
                if (mInside)
                {
                    indices[0] = i0++;
                    indices[1] = i2;
                    indices[2] = i1;
                    indices[3] = i1++;
                    indices[4] = i2++;
                    indices[5] = i3++;
                }
                else // outside view
                {
                    indices[0] = i0++;
                    indices[1] = i1;
                    indices[2] = i2;
                    indices[3] = i1++;
                    indices[4] = i3++;
                    indices[5] = i2++;
                }
            }
        }

        delete1(cs);
        delete1(sn);

        mesh = new0 TriMesh(mVFormat, vbuffer, ibuffer);
    }
    else
    {
        mesh = Sphere(axisSamples, radialSamples, radius);
        VertexBuffer* vbuffer = mesh->GetVertexBuffer();
        int numVertices = vbuffer->GetNumElements();

        VertexBufferAccessor vba(mVFormat, vbuffer);

        // Flatten sphere at poles.
        float hDiv2 = 0.5f*height;
        vba.Position<Float3>(numVertices-2)[2] = -hDiv2;  // south pole
        vba.Position<Float3>(numVertices-1)[2] = +hDiv2;  // north pole

        // Remap z-values to [-h/2,h/2].
        float zFactor = 2.0f/(axisSamples-1);
        float tmp0 = radius*(-1.0f + zFactor);
        float tmp1 = 1.0f/(radius*(+1.0f - zFactor));
        for (int i = 0; i < numVertices-2; ++i)
        {
            Float3& pos = vba.Position<Float3>(i);
            pos[2] = hDiv2*(-1.0f + tmp1*(pos[2] - tmp0));
            float adjust = radius*Mathf::InvSqrt(pos[0]*pos[0] +
                pos[1]*pos[1]);
            pos[0] *= adjust;
            pos[1] *= adjust;
        }
        TransformData(vba);

        if (mHasNormals)
        {
            mesh->UpdateModelSpace(Visual::GU_NORMALS);
        }
    }

    // The duplication of vertices at the seam causes the automatically
    // generated bounding volume to be slightly off center.  Reset the bound
    // to use the true information.
    float maxDist = Mathf::Sqrt(radius*radius + height*height);
    mesh->GetModelBound().SetCenter(APoint::ORIGIN);
    mesh->GetModelBound().SetRadius(maxDist);
    return mesh;
}