model/MySphere.js

/**
 * @class Represents a sphere.
 */
class MySphere extends CGFobject {
    /**
     * Instantiates a new sphere instance.
     * @param  {CGFscene} scene - the scene in which the sphere is going to be shown
     * @param  {integer} slices - number of slices around Y axis
     * @param  {integer} stacks - number of stacks along Y axis, from the center to the poles (half of sphere)
     */
    constructor(scene, slices, stacks, material) {
        super(scene);
        this.latDivs = stacks * 2;
        this.longDivs = slices;
        this.material = material;

        this.initBuffers();
    }

    /**
     * Initializes the sphere buffers.
     */
    initBuffers() {
        this.vertices = [];
        this.indices = [];
        this.normals = [];
        this.texCoords = [];

        var phi = 0;
        var theta = 0;
        var phiInc = Math.PI / this.latDivs;
        var thetaInc = (2 * Math.PI) / this.longDivs;
        var latVertices = this.longDivs + 1;

        var t = 0;

        // build an all-around stack at a time, starting on "north pole" and proceeding "south"
        for (let latitude = 0; latitude <= this.latDivs; latitude++) {
            var sinPhi = Math.sin(phi);
            var cosPhi = Math.cos(phi);
            var s = 0.55;

            // in each stack, build all the slices around, starting on longitude 0
            theta = 0;
            for (let longitude = 0; longitude <= this.longDivs; longitude++) {
                //--- Vertices coordinates
                var x = Math.cos(theta) * sinPhi;
                var y = cosPhi;
                var z = Math.sin(-theta) * sinPhi;
                this.vertices.push(x, y, z);

                //--- Indices
                if (latitude < this.latDivs && longitude < this.longDivs) {
                    var current = latitude * latVertices + longitude;
                    var next = current + latVertices;
                    // pushing two triangles using indices from this round (current, current+1)
                    // and the ones directly south (next, next+1)
                    // (i.e. one full round of slices ahead)

                    this.indices.push(current + 1, current, next);
                    this.indices.push(current + 1, next, next + 1);
                }

                //--- Normals
                // at each vertex, the direction of the normal is equal to 
                // the vector from the center of the sphere to the vertex.
                // in a sphere of radius equal to one, the vector length is one.
                // therefore, the value of the normal is equal to the position vectro
                this.normals.push(x, y, z);
                theta += thetaInc;

                //--- Texture Coordinates
                // To be done... 
                // May need some additional code also in the beginning of the function.
                s += 1 / this.longDivs;
                this.texCoords.push(s, t);
            }
            phi += phiInc;
            t += 1 / this.latDivs;
        }

        this.primitiveType = this.scene.gl.TRIANGLES;
        this.initGLBuffers();
    }

    /**
     * Displays the sphere.
     */
    display() {
        if (typeof this.material !== 'undefined')
            this.material.apply();
        super.display();
        this.scene.setDefaultAppearance();
    }

}