Sphere

Other than a point, the next most basic 3D shape. A sphere consists of a point and a radius. The radius of a sphere goes half-way accross it. So, a sphere with a radius of 1, will have a diameter of 2. This can be counter-intuitive when modelling a world, but keep it in mind!

SPHERE

Because we're not going to actually expose a lot of the data underneath the sphere, i'm going to store the point as a Vector3, and the radius as a float, but you could store the point as a Point

Based on the above information, and the image, the simplest implementation of a sphere would be:

// THIS BLOCK IS JUST SAMPLE CODE, DON'T COPY IT!
class Sphere { // Could be a struct?
  public Vector3 position; // Could be 3 floats?
  public float radius = 1f;
}

Code Guide

Everything in and after the Rendering region will compile. The code above it is more of a suggestion than a hard guide, tough i do think this is good design. The CreateRenderArrays function MUST be called in EVERY constructor.

using System;
using OpenTK.Graphics.OpenGL;
using Math_Implementation;

class Sphere {
    Vector3 point = new Vector3();
    float radius = 1f;

    public Point Position { /* TODO */ } // Gets / Sets point vector
    public float Radius { /* TODO */} // Self explanatory

    public Sphere() {
        CreateRenderArrays(); // Mush call this to create Arrays
    }

    public Sphere(Point p, float r) {
        // TODO: Set member variables
        CreateRenderArrays(); // Mush call this to create Arrays
    }

    public Sphere(Vector3 p, float r) {
        // TODO: Set member variables
        CreateRenderArrays(); // Mush call this to create Arrays
    }

    public Sphere(float x, float y, float z, float r) {
        // TODO: Set member variables
        CreateRenderArrays(); // Mush call this to create Arrays
    }

#region Rendering
    private float[] verts = null;
    private float[] norms = null;
    private uint[] indices = null;

    private void CreateVBO(uint rings = 10, uint sectors = 15) {
        // From:
        // http://stackoverflow.com/questions/5988686/creating-a-3d-sphere-in-opengl-using-visual-c/5989676#5989676
        // http://stackoverflow.com/questions/7957254/connecting-sphere-vertices-opengl
        float R = 1f/ (float)(rings - 1);
        float S = 1f/ (float)(sectors - 1);
        float M_PI = 3.14159265358979323846f;
        float M_PI_2 = 1.57079632679489661923f;

        verts = new float[rings * sectors * 3];
        norms= new float[rings * sectors * 3];
        indices = new uint[rings * sectors * 4];

        int v = 0;
        int n = 0;
        int i = 0;

        for (int r = 0; r < rings; r++) {
            for (int s = 0; s < sectors; s++) {
                float y = (float)Math.Sin(-M_PI_2 + M_PI * r * R);
                float x = (float)Math.Cos(2f * M_PI * s * S) * (float)Math.Sin(M_PI * r * R);
                float z = (float)Math.Sin(2f * M_PI * s * S) * (float)Math.Sin(M_PI * r * R);

                verts[v++] = (x /* * radius*/);
                verts[v++] = (y /* * radius*/);
                verts[v++] = (z /* * radius*/);

                norms[n++] = (x);
                norms[n++] = (y);
                norms[n++] = (z);
            }
        }

        if (v != verts.Length) {
            Console.WriteLine("ERROR, Wrong number of verts!");
        }
        if (n != norms.Length) {
            Console.WriteLine("ERROR, Wrong number of norms!");
        }

        for (int r = 0; r < rings - 1; r++) {
            for (int s = 0; s < sectors - 1; s++) {
                indices[i++] = ((uint)(r * sectors + s));
                indices[i++] = ((uint)(r * sectors + (s + 1)));
                indices[i++] = ((uint)((r + 1) * sectors + (s + 1)));
                indices[i++] = ((uint)((r + 1) * sectors + s));
            }
        }

        if (i != indices.Length) {
            Console.WriteLine("ERROR, Wrong number of indices!");
        }
    }

    public void Render() {
        GL.PushMatrix();
        GL.Translate(point.X, point.Y, point.Z);
        GL.Scale(radius, radius, radius);

        GL.EnableClientState(ArrayCap.VertexArray);
        GL.EnableClientState(ArrayCap.NormalArray);

        GL.VertexPointer(3, VertexPointerType.Float, 0, verts);
        GL.NormalPointer(NormalPointerType.Float, 0, norms);
        GL.DrawElements(PrimitiveType.Quads, indices.Length, DrawElementsType.UnsignedInt, indices);

        GL.DisableClientState(ArrayCap.VertexArray);
        GL.DisableClientState(ArrayCap.NormalArray);

        GL.PopMatrix();
    }
#endregion

    public override string ToString() {
        return "Position: (" + point.X + ", " + point.Y + ", " + point.Z + "), Radius: " + radius;
    }
}

On Your Own

Implement a sphere class. Feel free to use the above code as a guide, or come up with your own implementeation.

Sample / Unit Test

You can Download the samples for this chapter to see if your result looks like the unit test.

This sample is short and simple, it makes a new sphere at origin, configures some render settings and draws the sphere. There is an image of what it's supposed to look like after the code.

using OpenTK.Graphics.OpenGL;
using Math_Implementation;
// Include the namespace where your primitives live!

namespace CollisionDetectionSelector.Samples {
    class SphereSample : Application{
        Sphere sphere = new Sphere(new Point(4, 0, 0), 3);
        Sphere sphere2 = new Sphere();

        public override void Intialize(int width, int height) {
            GL.Enable(EnableCap.CullFace);
            GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
        }

        public override void Render() {
            Matrix4 lookAt = Matrix4.LookAt(new Vector3(0.0f, 5.0f, 20), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
            GL.LoadMatrix(lookAt.OpenGL);

            GL.Begin(PrimitiveType.Lines);
            Line(1f, 0f, 0f);
            Line(0f, 1f, 0f);
            Line(0f, 0f, 1f);
            GL.End();

            GL.Color3(0f, 0f, 1f);
            sphere2.Render();
            GL.Color3(1f, 0f, 0f);
            sphere.Render();
        }

        void Line(float x, float y, float z) {
            GL.Color3(x, y, z);
            GL.Vertex3(0f, 0f, 0f);
            GL.Vertex3(x, y, z);
        }

        public override void Resize(int width, int height) {
            GL.Viewport(0, 0, width, height);
            GL.MatrixMode(MatrixMode.Projection);
            float aspect = (float)width / (float)height;
            Matrix4 perspective = Matrix4.Perspective(60, aspect, 0.01f, 1000.0f);
            GL.LoadMatrix(Matrix4.Transpose(perspective).Matrix);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadIdentity();
        }
    }
}

UNIT_RESULT

results matching ""

    No results matching ""