C#
TAO
GLUT
Grafikk
Børre Stenseth
Utviklingsverktøy>C#/.Net

Bruk av OpenGL i .Net/C#

Hva

OpenGL synes ikke å stå på toppen av Microsofts prioriteringsliste så vi trenger bidrag fra andre for å gjøre OpenGL tilgjengelig fra C#. Det ser ut til at TAO [1] er en interessant løsning og jeg har basert meg på TAO i denne modulen.

TAO er kurant å laste ned og installere.

Eksemplene nedenfor forutsetter at vi installerer Taoframework,

  1. Last ned taoframework-2.1-setup.exe fra [1] .
  2. Kjør installasjonen. Denne foreslår å plassere filene under Program Files/TaoFramework. Jeg har under installasjonen sagt at jeg vil: "Register assemblies in global Assembly Cache". Det betyr at de vil være tilgjengelige på linje med andre globale biblioteker når jeg senere skal inkludere dem i et prosjekt

glut/minimum

glut1

Glut [2] er et enkelt vindussystem som kort sagt lar oss sette opp et enkelt vindu og programmere grafikk i det. Glut ble opprinnelig skrevet som et verktøy for c-programmerere i "vindusløse" omgivelser. Vi fraskriver oss alle de mulighetene vi har for å integrere grafikken i mer rike GUI-omgivelser. Det er enkelt å programmere i glut, men det er begrenset hva slags applikasjoner vi kan lage. Glut distribueres med TAO. Vi går fram som følger:

  1. Lager et console-program
  2. Legger til referanser: Tao.FreeGlut og Tao.OpenGL. Disse finner vi der vi plassere dem ved installasjonen
  3. Kopierer fila freeglut.dll til prosjektkatalogen, legger den til prosjektet og merker den slik at den kopieres til samme katalog som .exe-fila når prosjektet bygges.

Det enkle console programmet ser i sin helhet slik ut:

using System;
using System.Collections.Generic;
using System.Text;
using Tao.FreeGlut;
using Tao.OpenGl;
namespace taoglutsimple
{
    class Program
    {
        static float rotx;
        static float rotz;
        static void Main(string[] args)
        {
            Glut.glutInit();
            Glut.glutInitDisplayMode(Glut.GLUT_RGB | Glut.GLUT_SINGLE);
            Glut.glutInitWindowSize(320, 320);
            Glut.glutInitWindowPosition(50, 50);
            Glut.glutCreateWindow("Sphere");
            // once in a lifetime
            Init();
            // define callbacks
            Glut.glutDisplayFunc(new Glut.DisplayCallback(Display));
            Glut.glutReshapeFunc(new Glut.ReshapeCallback(Reshape));
            // start the glut main loop
            Glut.glutMainLoop();
        }
        private static void Init()
        {
            // set up material
            float[] mat_ambient = { 0.3f, 0.3f, 0.0f, 1.0f };
            float[] mat_diffuse = { 1.0f, 1.0f, 0.5f, 1.0f };
            float[] spec = { 0.6f, 0.6f, 0.5f, 1.0f };
            Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_AMBIENT, mat_ambient);
            Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_DIFFUSE, mat_diffuse);
            // set up light
            float[] ambient = { 0.2f, 0.2f, 0.2f, 1.0f };
            float[] diffuse = { 1.0f, 1.0f, 1.0f, 1.0f };
            float[] position = { 200.0f, 300.0f, 100.0f, 0.0f };
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, ambient);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, diffuse);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, position);
            Gl.glEnable(Gl.GL_LIGHT0);
            Gl.glEnable(Gl.GL_LIGHTING);
            // enable light 
            Gl.glEnable(Gl.GL_LIGHTING);
            Gl.glEnable(Gl.GL_LIGHT0);
            // depth sorting
            Gl.glEnable(Gl.GL_DEPTH_TEST);
            Gl.glDepthFunc(Gl.GL_LESS);
            // background
            Gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        }
        #region callbacks
        // callbacks
 
        private static void Display()
        {
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT |
                        Gl.GL_DEPTH_BUFFER_BIT |
                        Gl.GL_ACCUM_BUFFER_BIT);
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity();
            Glu.gluLookAt(0, 0, 5, // eyepos
                          0, 0, 0, // look at
                          0, 1, 0);// up-vector
            Glu.GLUquadric quad = Glu.gluNewQuadric();
            Glu.gluQuadricDrawStyle(quad, Glu.GLU_FILL);
            Glu.gluQuadricNormals(quad, Glu.GLU_SMOOTH);
            Glu.gluQuadricOrientation(quad, Glu.GLU_OUTSIDE);
            Glu.gluQuadricTexture(quad, Glu.GLU_TRUE);
            Glu.gluSphere(quad, 1.0, 20, 20);
            Glu.gluDeleteQuadric(quad);
            Gl.glFlush();
            Glut.glutSwapBuffers();
        }
        private static void Reshape(int width, int height)
        {
            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();
            Gl.glViewport(0, 0, width, height);
            Glu.gluPerspective(30.0f, (double)width / height, 0.1f, 70.0f);
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
        }
        #endregion callbacks
    }
}

Som vanlig er det 3 nødvendige funksjoner som skal ivaretas: init, display og reshape. De to siste er callbacks, siden de skal utføres som konsekvens av (bruker)handlinger. Det er glutMainLoop() som har kontroll helt til vi avslutter programmet ved å lukke vinduet. Vi har en rekke flere muligheter for å plukke opp begivenheter ved callbacks.

glut/teapot

teapot

glut-pakka har en egen rutine for å tegne den klassiske tekanna [3] . Koden er i sin helhet slik:

_Program-teapot.cs

Merk at vi her har lagt inn en timer-callback.

form

cylinder

Når vi skal integrere OpenGL i vindusstrukturen til .Net blir det noe mer konfigurering å ta hensyn til. Vi må sette opp det aktuelle vinduet, Form, slik at det kan vise OpenGL, og vi må finne en OpenGL konfigurasjon som er kompatibel med de grafikkmulighetene Formen tilbyr. Dette kan gjøres på flere måter, men det enkelste synes å være å bruke en GUI-komponent som distribures som del av TAO Framework. Forutsatt at TAO Framework er installert, kan vi gå fram slik:

  1. Lag en Windows applikasjon
  2. Importer referanser: Tao.OpenGL og Tao.Platform.Windows
  3. Set up Tools fra Tao.Platform.Windows
  4. Plasser den genererte komponenten på formen

Vi legger i tillegg til en vertikal og en horisontal slider og vi tegner ut en sylinder i opengl-componenten. Vi får følgende kode i Form.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Tao.OpenGl;
using Tao.Platform.Windows;
namespace taoform1
{
    public partial class Form1 : Form
    {
        float rotx = 0.0f;
        float roty = 0.0f;
        public Form1()
        {
            InitializeComponent();
            simpleOpenGlControl1.InitializeContexts();
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (components != null)
            {
                simpleOpenGlControl1.DestroyContexts();
            }
        }
        private void simpleOpenGlControl1_Paint(object sender, PaintEventArgs e)
        {
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT |
                         Gl.GL_DEPTH_BUFFER_BIT |
                         Gl.GL_ACCUM_BUFFER_BIT);
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity();
            Glu.gluLookAt(0, 0, 5, // eyepos
                          0, 0, 0, // look at
                          0, 1, 0);// up-vector
            Gl.glRotatef(rotx, 1.0f, 0.0f, 0.0f);
            Gl.glRotatef(roty, 0.0f, 1.0f, 0.0f);
            
            Glu.GLUquadric quad = Glu.gluNewQuadric();
            Glu.gluQuadricDrawStyle(quad, Glu.GLU_FILL);
            Glu.gluQuadricNormals(quad, Glu.GLU_SMOOTH);
            Glu.gluQuadricOrientation(quad, Glu.GLU_OUTSIDE);
            Glu.gluCylinder(quad, 1.0f, 1.0f, 1.0f, 20, 20);
            Gl.glFlush();
            Glu.gluDeleteQuadric(quad);
        }
        private void simpleOpenGlControl1_Resize(object sender, EventArgs e)
        {
            setPerspective();  
        }
        private void setPerspective()
        {
            int height = simpleOpenGlControl1.Height;
            int width = simpleOpenGlControl1.Width;
            Gl.glViewport(0, 0, width, height);
            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();
            Glu.gluPerspective(35, (double)width / (double)height, 1.0, 100);
            //Gl.glOrtho(-2.0, 2.0, 2.0, -2.0, -10.0, 100.0);
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
        }
        private void simpleOpenGlControl1_Load(object sender, EventArgs e)
        {
            // set up material
            float[] mat_ambient = { 0.3f, 0.3f, 0.0f, 1.0f };
            float[] mat_diffuse = { 1.0f, 1.0f, 0.5f, 1.0f };
            float[] spec = { 0.6f, 0.6f, 0.5f, 1.0f };
            Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_AMBIENT, mat_ambient);
            Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_DIFFUSE, mat_diffuse);
            // set up light
            float[] ambient = { 0.2f, 0.2f, 0.2f, 1.0f };
            float[] diffuse = { 1.0f, 1.0f, 1.0f, 1.0f };
            float[] position = { 200.0f, 300.0f, 100.0f, 0.0f };
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, ambient);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, diffuse);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, position);
            Gl.glEnable(Gl.GL_LIGHT0);
            Gl.glEnable(Gl.GL_LIGHTING);
            // enable light 
            Gl.glEnable(Gl.GL_LIGHTING);
            Gl.glEnable(Gl.GL_LIGHT0);
            // depth sorting
            Gl.glEnable(Gl.GL_DEPTH_TEST);
            Gl.glDepthFunc(Gl.GL_LESS);
            // background
            Gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
            setPerspective();
        }
        private void trackBarX_Scroll(object sender, EventArgs e)
        {
            rotx = trackBarX.Value;
            simpleOpenGlControl1.Invalidate();
        }
        private void trackBarY_Scroll(object sender, EventArgs e)
        {
            roty = trackBarY.Value;
            simpleOpenGlControl1.Invalidate();
        }
    }
}
[4]
Enkel glut: https://svnit.hiof.no/svn/psource/CsharpGrafikk/taoglutsimple
Tekanna: https://svnit.hiof.no/svn/psource/CsharpGrafikk/taoglutteapot
Form med sylinder: https://svnit.hiof.no/svn/psource/CsharpGrafikk/taoform1

Noen andre CSharp-prosjekter

  • Prosjektet til Student Rune Dragsnes er bygget med TAO og C#, se Invers pendel.
  • Modulen Klokke beskriver et prosjekt bygget med TAO og C#.
Referanser
  1. Tao FrameworkSourceForge.netBindings to facilitate cross-platform development utilizing the .NET platformsourceforge.net/projects/taoframework/14-03-2010
  1. GLUT - The OpenGL Utility ToolkitKhronos Group.www.opengl.org/resources/libraries/glut.html14-09-2009
  1. The History of The Teapot2009www.sjbaker.org/wiki/index.php?title=The_History_of_The_Teapot14-03-2009
  1. MonoMono CummunityCross platform .Net development framweworkwww.mono-project.com/Main_Page14-03-2010
Vedlikehold
B.Stenseth april 2010
Utviklingsverktøy>C#/.Net
til toppen