How to draw the middle half of a sphere (in code)

回眸只為那壹抹淺笑 提交于 2019-12-13 12:44:03

问题


I'm trying to create the middle half of a sphere. Basically to create a sphere, stack numbers and slice numbers are given, and there are two variables phi (for slices) and theta (for stacks) responsible for how much to progress. And the process is divided into creating bottom cap, body, and top cap (as seen below). To achieve middle half (theta of middle 50% as below), we need to omit the caps, and somehow modify the body. I was playing around with stack numbers (1/4*stackNumbers to 3/4*stackNumbers) but didn't give the result I wanted.

How should I modify the sphere generation to achieve the middle half (pi/4 <theta <pi*3/4)? My overall problem is how can I split the sphere into 3 different parts upper 25%, middle 50%, and bottom 25%? (25% in terms of angle, i.e. theta)

Here is the popular code for generating a sphere programmatically:

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;
        }
    }

} 

回答1:


The code here is using spherical coordinates to calculate the sphere. theta is the variable that represents the up/down coordinate that you're interested in, and theta goes from 0 to PI. You want to go from PI/4 to 3PI/4. stackNumbers simply represent the number of divisions in the sphere, since you can see that it is used as a denominator for stack, which is the wrong variable to change. So you can make the following changes to the code instead. From:

double theta0 = stackPercentage0 * Math.PI;
double theta1 = stackPercentage1 * Math.PI;

to:

double startTheta = Math.PI / 4;
double endTheta = 3 * Math.PI / 4;
double theta0 = stackPercentage0 * (endTheta - startTheta) + startTheta;
double theta1 = stackPercentage1 * (endTheta - startTheta) + startTheta;

And since you aren't using the caps you need to change the start and end stack numbers to reflect that:

for (int stack = 1; stack < stackNumber - 1; stack++) { // old
for (int stack = 0; stack < stackNumber; stack++) { // new

Also, you because you have more body faces now, you need to update the appropriate container for them. Replace (stackNumber - 2) with (stackNumber - 1).



来源:https://stackoverflow.com/questions/38149600/how-to-draw-the-middle-half-of-a-sphere-in-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!