Click here to Skip to main content
Click here to Skip to main content

Shading Subdivide Sphere

, 23 Mar 2008
Rate this:
Please Sign up or sign in to vote.
Flat and Smooth Shading
im04.PNG

Introduction

Polygonal Shading

  • Curved surfaces are approximated by polygons
  • How do we shade?
    • Flat shading
    • Smooth shading
  • Two questions:
    • How do we determine normals at vertices?
    • How do we calculate shading at interior points?

Steps

im01.PNG

im02.PNG

im03.PNG

Using the Code

using CsGL.OpenGL;

namespace GL_shading_subdivide
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Text += " - Press S F Left Right";
            float X = 0.525731112119133696f;
            float Z = 0.850650808352039932f;

            /* vertex data array */
            vdata = new float[12][] {
  new float[3]{-X, 0.0f, Z},  new float[3]{X, 0.0f, Z}, 
	new float[3] {-X, 0.0f, -Z}, new float[3] {X, 0.0f, -Z},
  new float[3]{0.0f, Z, X}, new float[3] {0.0f, Z, -X}, 
	new float[3] {0.0f, -Z, X}, new float[3] {0.0f, -Z, -X},
  new float[3] {Z, X, 0.0f}, new float[3] {-Z, X, 0.0f}, 
	new float[3] {Z, -X, 0.0f}, new float[3] {-Z, -X, 0.0f}};

            /* triangle indices */
            tindices = new int[20][]{
  new int[3] {1,4,0}, new int[3] {4,9,0}, new int[3] {4,5,9}, 
	new int[3] {8,5,4}, new int[3] {1,8,4},
  new int[3] {1,10,8}, new int[3] {10,3,8}, new int[3] {8,3,5}, 
	new int[3] {3,2,5}, new int[3] {3,7,2},
  new int[3] {3,10,7}, new int[3] {10,6,7}, new int[3]  {6,11,7},  
	new int[3]{6,0,11}, new int[3] {6,1,0},
  new int[3] {10,1,6}, new int[3] {11,0,9}, new int[3] {2,11,9}, 
	new int[3] {5,2,9}, new int[3] {11,2,7}};

            ClientSize = new Size(640, 480);
            init();
            reshape(640, 480);
        }

        /* vertex data array */
        float[][] vdata = new float[12][];

        /* triangle indices */
        int[][] tindices = new int[20][];

        float[] mat_specular = { 0.5f, 0.5f, 0.5f, 1.0f };
        float[] mat_diffuse = { 0.8f, 0.6f, 0.4f, 1.0f };
        float[] mat_ambient = { 0.8f, 0.6f, 0.4f, 1.0f };
        float mat_shininess = 20.0f;    // unused if specular is 0 

        float[] light_ambient = { 0.2f, 0.2f, 0.2f, 1.0f };
        float[] light_diffuse = { 1.0f, 1.0f, 1.0f, 1.0f };
        float[] light_specular = { 0.4f, 0.4f, 0.4f, 1.0f };

        //   float[] light_position = { 100f, 50f, -1.0f, 0.0f }; // directional

        int flat = 1;            /* 0 = smooth shading, 1 = flat shading */
        int subdiv = 0;            /* number of subdivisions */

        private void openGLControl1_Paint(object sender, PaintEventArgs e)
        {
            Draw();
        }

        void Draw()
        {
            GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
            GL.glLoadIdentity();
            GL.glTranslatef(0f, 0.0f, 0);
            //  GL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_position);

            /* drawIco(); */
            /* drawSphere(); */
            GL.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, light_ambient);
            GL.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, light_diffuse);
            GL.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, light_specular);

            GL.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mat_specular);
            GL.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, mat_ambient);
            GL.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, mat_diffuse);
            GL.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, mat_shininess);

            GL.glEnable(GL.GL_LIGHTING);    /* enable lighting */
            GL.glEnable(GL.GL_LIGHT0);        /* enable light 0 */

            for (int i = 0; i < 20; i++)
            {
                subdivide(ref vdata[tindices[i][0]],
                          ref vdata[tindices[i][1]],
                          ref vdata[tindices[i][2]],
                             subdiv);
            }

            GL.glDisable(GL.GL_LIGHTING);    /* glDisable lighting */
            GL.glDisable(GL.GL_LIGHT0);        /* glDisable light 0 */

            GL.glFlush();
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            openGLControl1.Invalidate();
        }

        void init()
        {
            GL.glShadeModel(GL.GL_SMOOTH);    /* enable smooth shading */

            GL.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
            GL.glClearDepth(1.0f);                    // Depth Buffer Setup

            GL.glEnable(GL.GL_DEPTH_TEST);            // Enables Depth Testing
            GL.glDepthFunc(GL.GL_LEQUAL);             // The Type Of Depth Testing To Do
        }
        void reshape(int w, int h)
        {
            float aspect = (float)w / (float)h;
            GL.glViewport(0, 0, w, h);

            GL.glMatrixMode(GL.GL_PROJECTION);
            GL.glLoadIdentity();
            if (w <= h)
                GL.glOrtho(-1.25, 1.25, -1.25 * aspect, 1.25 * aspect, -2.0, 2.0);
            else
                GL.glOrtho(-1.25 * aspect, 1.25 * aspect, -1.25, 1.25, -2.0, 2.0);
            GL.glMatrixMode(GL.GL_MODELVIEW);

            GL.gluLookAt(0.5, 0.5, -1.5, /* eye */
                    0.0, 0.0, 0.0,  /* at */
                0.0, 1.0, 0.0); /* up */

            GL.glMatrixMode(GL.GL_MODELVIEW);
            GL.glLoadIdentity();
        }

        /* normalize a vector of non-zero length */
        void normalize(float[] v)
        {
            float d = (float)Math.Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
            /* omit explicit check for division by zero */

            v[0] /= d; v[1] /= d; v[2] /= d;
        }

        /* normalized cross product of non-parallel vectors */
        void normCrossProd(float[] u, float[] v, float[] n)
        {
            n[0] = u[1] * v[2] - u[2] * v[1];
            n[1] = u[2] * v[0] - u[0] * v[2];
            n[2] = u[0] * v[1] - u[1] * v[0];
            normalize(n);
        }

        void normFace(float[] v1, float[] v2, float[] v3)
        {
            float[] d1 = new float[3], d2 = new float[3], n = new float[3];
            int k;
            for (k = 0; k < 3; k++)
            {
                d1[k] = v1[k] - v2[k];
                d2[k] = v2[k] - v3[k];
            }
            normCrossProd(d1, d2, n);
            GL.glNormal3fv(n);
        }

        /* draw triangle using face normals */
        void drawTriangleFlat(float[] v1, float[] v2, float[] v3)
        {
            GL.glBegin(GL.GL_TRIANGLES);
            normFace(v1, v2, v3);
            GL.glVertex3fv(v1);
            GL.glVertex3fv(v2);
            GL.glVertex3fv(v3);
            GL.glEnd();
        }

        /* draw triangle using sphere normals */
        void drawTriangleSmooth(float[] v1, float[] v2, float[] v3)
        {
            GL.glBegin(GL.GL_TRIANGLES);
            GL.glNormal3fv(v1);
            GL.glVertex3fv(v1);
            GL.glNormal3fv(v2);
            GL.glVertex3fv(v2);
            GL.glNormal3fv(v3);
            GL.glVertex3fv(v3);
            GL.glEnd();
        }

        /* recursively subdivide face depth times */
        /* and draw the resulting triangles */
        void subdivide(ref float[] v1, ref float[] v2, ref float[] v3, int depth)
        {
            float[] v12 = new float[3], v23 = new float[3], v31 = new float[3];

            if (depth == 0)
            {
                if (flat == 1)
                    drawTriangleFlat(v1, v2, v3);
                else
                    drawTriangleSmooth(v1, v2, v3);
            }

            /* calculate midpoints of each side */
            for (int i = 0; i < 3; i++)
            {
                v12[i] = (v1[i] + v2[i]) / 2.0f;
                v23[i] = (v2[i] + v3[i]) / 2.0f;
                v31[i] = (v3[i] + v1[i]) / 2.0f;
            }
            // extrude midpoints to lie on unit sphere 
            normalize(v12);
            normalize(v23);
            normalize(v31);

            // recursively subdivide new triangles 
            if (depth != 0)
            {
                subdivide(ref v1, ref v12, ref v31, depth - 1);
                subdivide(ref v2, ref v23, ref v12, depth - 1);
                subdivide(ref v3, ref v31, ref v23, depth - 1);
                subdivide(ref v12, ref v23, ref v31, depth - 1);
            }
        }

        protected override bool ProcessDialogKey(Keys keyData)
        {
            if (keyData == Keys.Left)
            {
                subdiv++;
                if (subdiv > 6)
                    subdiv = 6;
            }
            if (keyData == Keys.Right)
            { 
                subdiv--;
                if (subdiv < 0)
                    subdiv = 0;
            }

            if (keyData == Keys.F)
                flat = 1;

            if (keyData == Keys.S)
                flat = 0;

            return base.ProcessDialogKey(keyData);
        }
    }
}

History

  • 24th March, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

salim_chaf
Web Developer
Algeria Algeria
No Biography provided

Comments and Discussions

 
QuestionGreat article PinmemberYuval Rivlin6-Nov-13 4:33 
QuestionChanging size and position of sphere Pinmembersafee ullah21-Jul-11 16:56 
GeneralMissing dll Pinmemberdave.kelly26-Mar-08 0:07 
csgl.native.dll is missing from the project, which causes an initialization exception.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140814.1 | Last Updated 24 Mar 2008
Article Copyright 2008 by salim_chaf
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid