Dibuja la mitad central de una esfera mediante programación

10

Estoy tratando de crear la mitad media de una esfera. Básicamente, para crear una esfera, se dan números de pila y números de rebanada, y hay dos variables phi(para las rebanadas) y theta(para las pilas) responsables de cuánto progresar. Y el proceso se divide en la creación de la tapa inferior, el cuerpo y la tapa superior (como se ve a continuación). Para lograr la mitad media ( thetadel 50% medio como se muestra a continuación), debemos omitir las tapas y, de alguna manera, modificar el cuerpo. Estaba jugando con los números de pila ( 1/4*stackNumbers to 3/4*stackNumbers) pero no obtuve el resultado que quería.

¿Cómo debo modificar la generación de la esfera para alcanzar la mitad del medio ( pi/4 <theta <pi*3/4)? Mi problema general es ¿cómo puedo dividir la esfera en 3 partes diferentes: 25% superior, 50% medio e 25% inferior?

Aquí está el código popular para generar una esfera mediante programación:

ingrese la descripción de la imagen aquí

private void generateSphere(int stackNumber, int sliceNumber, boolean facingOut) {
    int capVertexNumber = 3 * sliceNumber;
    int bodyVertexNumber = 4 * sliceNumber * (stackNumber - 2);
    int vertexNumber = (2 * capVertexNumber) + bodyVertexNumber;
    int triangleNumber = (2 * capVertexNumber) + (6 * sliceNumber * (stackNumber - 2));

    vertices = new float[3 * vertexNumber];
    normals = new float[3 * vertexNumber];
    texCoords = new float[2 * vertexNumber];
    indices = new char[triangleNumber];

    // bottom cap
    // createCap(stackNumber, sliceNumber, false, facingOut);

    // body
    createBody(stackNumber, sliceNumber, facingOut);

    // top cap
    createCap(stackNumber, sliceNumber, true, facingOut);
}

private void createCap(int stackNumber, int sliceNumber, boolean top, boolean facingOut) {

    float stackPercentage0;
    float stackPercentage1;

    if (!top) {
        stackPercentage0 = ((float) (stackNumber - 1) / stackNumber);
        stackPercentage1 = 1.0f;

    } else {
        stackPercentage0 = (1.0f / stackNumber);
        stackPercentage1 = 0.0f;
    }

    float t0 = stackPercentage0;
    float t1 = stackPercentage1;
    double theta0 = stackPercentage0 * Math.PI;
    double theta1 = stackPercentage1 * Math.PI;
    double cosTheta0 = Math.cos(theta0);
    double sinTheta0 = Math.sin(theta0);
    double cosTheta1 = Math.cos(theta1);
    double sinTheta1 = Math.sin(theta1);

    for (int slice = 0; slice < sliceNumber; slice++) {
        float slicePercentage0 = ((float) (slice) / sliceNumber);
        float slicePercentage1 = ((float) (slice + 1) / sliceNumber);
        double phi0 = slicePercentage0 * 2.0 * Math.PI;
        double phi1 = slicePercentage1 * 2.0 * Math.PI;
        float s0, s1;
        if (facingOut) {
            s0 = 1 - slicePercentage0;
            s1 = 1 - slicePercentage1;
        } else {
            s0 = slicePercentage0;
            s1 = slicePercentage1;
        }
        float s2 = (s0 + s1) / 2.0f;
        double cosPhi0 = Math.cos(phi0);
        double sinPhi0 = Math.sin(phi0);
        double cosPhi1 = Math.cos(phi1);
        double sinPhi1 = Math.sin(phi1);

        float x0 = (float) (sinTheta0 * cosPhi0);
        float y0 = (float) cosTheta0;
        float z0 = (float) (sinTheta0 * sinPhi0);

        float x1 = (float) (sinTheta0 * cosPhi1);
        float y1 = (float) cosTheta0;
        float z1 = (float) (sinTheta0 * sinPhi1);

        float x2 = (float) (sinTheta1 * cosPhi0);
        float y2 = (float) cosTheta1;
        float z2 = (float) (sinTheta1 * sinPhi0);

        vertices[vertexCount + 0] = x0;
        vertices[vertexCount + 1] = y0;
        vertices[vertexCount + 2] = z0;

        vertices[vertexCount + 3] = x1;
        vertices[vertexCount + 4] = y1;
        vertices[vertexCount + 5] = z1;

        vertices[vertexCount + 6] = x2;
        vertices[vertexCount + 7] = y2;
        vertices[vertexCount + 8] = z2;

        if (facingOut) {
            normals[vertexCount + 0] = x0;
            normals[vertexCount + 1] = y0;
            normals[vertexCount + 2] = z0;

            normals[vertexCount + 3] = x1;
            normals[vertexCount + 4] = y1;
            normals[vertexCount + 5] = z1;

            normals[vertexCount + 6] = x2;
            normals[vertexCount + 7] = y2;
            normals[vertexCount + 8] = z2;
        } else {
            normals[vertexCount + 0] = -x0;
            normals[vertexCount + 1] = -y0;
            normals[vertexCount + 2] = -z0;

            normals[vertexCount + 3] = -x1;
            normals[vertexCount + 4] = -y1;
            normals[vertexCount + 5] = -z1;

            normals[vertexCount + 6] = -x2;
            normals[vertexCount + 7] = -y2;
            normals[vertexCount + 8] = -z2;
        }

        texCoords[texCoordCount + 0] = s0;
        texCoords[texCoordCount + 1] = t0;
        texCoords[texCoordCount + 2] = s1;
        texCoords[texCoordCount + 3] = t0;
        texCoords[texCoordCount + 4] = s2;
        texCoords[texCoordCount + 5] = t1;

        if ((facingOut && top) || (!facingOut && !top)) {
            indices[indexCount + 0] = (char) (triangleCount + 1);
            indices[indexCount + 1] = (char) (triangleCount + 0);
            indices[indexCount + 2] = (char) (triangleCount + 2);
        } else {
            indices[indexCount + 0] = (char) (triangleCount + 0);
            indices[indexCount + 1] = (char) (triangleCount + 1);
            indices[indexCount + 2] = (char) (triangleCount + 2);
        }

        vertexCount += 9;
        texCoordCount += 6;
        indexCount += 3;
        triangleCount += 3;
    }

}

private void createBody(int stackNumber, int sliceNumber, boolean facingOut) {
    for (int stack = 1; stack < stackNumber - 1; stack++) {
        float stackPercentage0 = ((float) (stack) / stackNumber);
        float stackPercentage1 = ((float) (stack + 1) / stackNumber);

        float t0 = stackPercentage0;
        float t1 = stackPercentage1;

        double theta0 = stackPercentage0 * Math.PI;
        double theta1 = stackPercentage1 * Math.PI;
        double cosTheta0 = Math.cos(theta0);
        double sinTheta0 = Math.sin(theta0);
        double cosTheta1 = Math.cos(theta1);
        double sinTheta1 = Math.sin(theta1);

        for (int slice = 0; slice < sliceNumber; slice++) {
            float slicePercentage0 = ((float) (slice) / sliceNumber);
            float slicePercentage1 = ((float) (slice + 1) / sliceNumber);
            double phi0 = slicePercentage0 * 2.0 * Math.PI;
            double phi1 = slicePercentage1 * 2.0 * Math.PI;
            float s0, s1;
            if (facingOut) {
                s0 = 1.0f - slicePercentage0;
                s1 = 1.0f - slicePercentage1;
            } else {
                s0 = slicePercentage0;
                s1 = slicePercentage1;
            }
            double cosPhi0 = Math.cos(phi0);
            double sinPhi0 = Math.sin(phi0);
            double cosPhi1 = Math.cos(phi1);
            double sinPhi1 = Math.sin(phi1);

            float x0 = (float) (sinTheta0 * cosPhi0);
            float y0 = (float) cosTheta0;
            float z0 = (float) (sinTheta0 * sinPhi0);

            float x1 = (float) (sinTheta0 * cosPhi1);
            float y1 = (float) cosTheta0;
            float z1 = (float) (sinTheta0 * sinPhi1);

            float x2 = (float) (sinTheta1 * cosPhi0);
            float y2 = (float) cosTheta1;
            float z2 = (float) (sinTheta1 * sinPhi0);

            float x3 = (float) (sinTheta1 * cosPhi1);
            float y3 = (float) cosTheta1;
            float z3 = (float) (sinTheta1 * sinPhi1);

            vertices[vertexCount + 0] = x0;
            vertices[vertexCount + 1] = y0;
            vertices[vertexCount + 2] = z0;

            vertices[vertexCount + 3] = x1;
            vertices[vertexCount + 4] = y1;
            vertices[vertexCount + 5] = z1;

            vertices[vertexCount + 6] = x2;
            vertices[vertexCount + 7] = y2;
            vertices[vertexCount + 8] = z2;

            vertices[vertexCount + 9] = x3;
            vertices[vertexCount + 10] = y3;
            vertices[vertexCount + 11] = z3;

            if (facingOut) {
                normals[vertexCount + 0] = x0;
                normals[vertexCount + 1] = y0;
                normals[vertexCount + 2] = z0;

                normals[vertexCount + 3] = x1;
                normals[vertexCount + 4] = y1;
                normals[vertexCount + 5] = z1;

                normals[vertexCount + 6] = x2;
                normals[vertexCount + 7] = y2;
                normals[vertexCount + 8] = z2;

                normals[vertexCount + 9] = x3;
                normals[vertexCount + 10] = y3;
                normals[vertexCount + 11] = z3;
            } else {
                normals[vertexCount + 0] = -x0;
                normals[vertexCount + 1] = -y0;
                normals[vertexCount + 2] = -z0;

                normals[vertexCount + 3] = -x1;
                normals[vertexCount + 4] = -y1;
                normals[vertexCount + 5] = -z1;

                normals[vertexCount + 6] = -x2;
                normals[vertexCount + 7] = -y2;
                normals[vertexCount + 8] = -z2;

                normals[vertexCount + 9] = -x3;
                normals[vertexCount + 10] = -y3;
                normals[vertexCount + 11] = -z3;
            }

            texCoords[texCoordCount + 0] = s0;
            texCoords[texCoordCount + 1] = t0;
            texCoords[texCoordCount + 2] = s1;
            texCoords[texCoordCount + 3] = t0;
            texCoords[texCoordCount + 4] = s0;
            texCoords[texCoordCount + 5] = t1;
            texCoords[texCoordCount + 6] = s1;
            texCoords[texCoordCount + 7] = t1;

            // one quad looking from outside toward center
            //
            // @formatter:off
            //
            // s1 --> s0
            //
            // t0 1-----0
            // | | |
            // v | |
            // t1 3-----2
            //
            // @formatter:on
            //
            // Note that tex_coord t increase from top to bottom because the
            // texture image is loaded upside down.
            if (facingOut) {
                indices[indexCount + 0] = (char) (triangleCount + 0);
                indices[indexCount + 1] = (char) (triangleCount + 1);
                indices[indexCount + 2] = (char) (triangleCount + 2);

                indices[indexCount + 3] = (char) (triangleCount + 2);
                indices[indexCount + 4] = (char) (triangleCount + 1);
                indices[indexCount + 5] = (char) (triangleCount + 3);
            } else {
                indices[indexCount + 0] = (char) (triangleCount + 0);
                indices[indexCount + 1] = (char) (triangleCount + 2);
                indices[indexCount + 2] = (char) (triangleCount + 1);

                indices[indexCount + 3] = (char) (triangleCount + 2);
                indices[indexCount + 4] = (char) (triangleCount + 3);
                indices[indexCount + 5] = (char) (triangleCount + 1);
            }

            vertexCount += 12;
            texCoordCount += 8;
            indexCount += 6;
            triangleCount += 4;
        }
    }

} 
Tina J
fuente

Respuestas:

1

Piensa en tu pregunta en términos de teselación con tu esfera formada por anillos. Si tiene un factor de teselación de 5, tendrá una tapa superior, 2 secciones centrales y una tapa inferior. Los dos anillos de teselación inferiores son la tapa inferior del 25% y los dos anillos de teselación superiores la tapa superior del 25%. Por lo tanto, el centro es un anillo en el ecuador con un conjunto de caras a cada lado al 50%. Aquí hay una muestra de cómo teselar una esfera calculando primero los anillos a cada altura y luego generando las caras entre cada anillo.

float radius = 1.0f;
const int tesselationFactor = 5;

for (int i = 0; i <= tesselationFactor; i++)
{
    const float PI = 3.14159265359f;
    const float PIDIV2 = PI / 2.0f;

    // find height of ring
    float height = (i*PI / tesselationFactor) - PIDIV2;
    float dy = sinf(height);
    float theta = cosf(height);

    // locate verticies equally around center to form a ring
    for (int j = 0; j <= tessellation * 2; j++)
    {

        float longitude = static_cast<float>(j) * PIDIV2 / (tessellation * 2);
        float dx = sinf(longitude) * theta;
        float dz = cosf(longitude) * theta;

        Vector normal{ dx, dy, dz }; // initialize vector
        vertices.push_back(VertexPositionNormal(normal * radius, normal));
    }
}
// Fill the index buffer with triangles joining each pair of latitude rings.
int stride = tessellation * 2 + 1;
for (int i = 0; i < tesselationFactor; i++) // verticle rings
{
    for (int j = 0; j <= tessellation * 2; j++) // horizontal verticies
    {
        // 
        int i1 = i + 1;
        int j1 = (j + 1) % stride;
        /* connecting face */
         // triangle 1
        index_push_back(indices, i * stride + j);
        index_push_back(indices, i1 * stride + j);
        index_push_back(indices, i * stride + j1);
         // triangle 2
        index_push_back(indices, i * stride + j1);
        index_push_back(indices, i1 * stride + j);
        index_push_back(indices, i1 * stride + j1);
    }
}
Chris
fuente