using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using OpenGL4NET; namespace ZPG { /// /// Hlavni okno /// class Osvetleni : System.Windows.Forms.Form { // Pocet vzorku na ose uint n = 150; // Context RenderingContext rc; // Mereni casu Time time; // Objekt Vlna vlna; /// /// Inicializace /// /// True, pokud uspech, jinak false public bool Init() { try { ClientSize = new System.Drawing.Size(800, 800); rc = RenderingContext.CreateContext(this, new RenderingContextSetting() { multisample = 0 }); vlna = new Vlna(n); // Zapnuti svetel gl.Enable(GL.LIGHTING); gl.Enable(GL.LIGHT0); // Povoleni obarvovani telesa dle barev vrcholu, v opacnem pripade je treba nastavit pro kazdy objekt material pomoci glMaterial* gl.Enable(GL.COLOR_MATERIAL); // Povoleni hloubkovehoi testu gl.Enable(GL.DEPTH_TEST); time = new Time(); } catch (Exception e) { Console.WriteLine(e.Message); return false; } return true; } /// /// Kresleni sceny /// void Render() { // Dalsi snimek time.NextFrame(); // Vycisteni bufferu gl.Clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT); // Nastaveni projekce gl.MatrixMode(GL.PROJECTION); gl.LoadIdentity(); gl.LoadMatrixf(Matrix.Perspective(45,(float)ClientSize.Width/ClientSize.Height, 1,2*n)); // Nastaveni modelview gl.MatrixMode(GL.MODELVIEW); gl.LoadIdentity(); gl.Translatef(-n / 2, n/3, -2f*n); gl.Rotated(30, 1, 0, 0); // Vypocet pozice svetla, homogenni souradnice udava, zda se jedna o vektor (0) ci vrchol v E3 (1) Vector4 lightPos = new Vector4((float)Math.Sin(time.FrameTime / 1000.0) * n / 4 + n / 2, 2*n / 30, (float)Math.Cos(time.FrameTime / 1000.0) * n / 4 + n / 2, 1); // Nastaveni pozice svetla gl.Lightfv(GL.LIGHT0, GL.POSITION, new float[] {lightPos.x, lightPos.y, lightPos.z, lightPos.w}); // Nastaveni utlumu se vzdalenosti gl.Lightf(GL.LIGHT0, GL.CONSTANT_ATTENUATION, 0); gl.Lightf(GL.LIGHT0, GL.LINEAR_ATTENUATION, 0.05f); gl.Lightf(GL.LIGHT0, GL.QUADRATIC_ATTENUATION, 0.005f); // Vykresleni objektu reprezentujiciho svetlo gl.PointSize(8); gl.Disable(GL.LIGHTING); gl.Begin(GL.POINTS); gl.Color3f(1, 1, 1); gl.Vertex3d(lightPos.x, lightPos.y, lightPos.z); gl.End(); gl.Enable(GL.LIGHTING); vlna.Render(); rc.SwapBuffers(); } /// /// Prekryti metody na zpracovani zprav /// /// Zprava protected override void WndProc(ref System.Windows.Forms.Message m) { switch (m.Msg) { // Pokud WM_PAINT, prekresli scenu case Windows.WM_PAINT: Render(); break; default: base.WndProc(ref m); break; } } /// /// Vstupni bod programu /// /// Na parametry nereaguje static void Main(string[] args) { Osvetleni prg = new Osvetleni(); if (prg.Init()) System.Windows.Forms.Application.Run(prg); } } /// /// Trida pro kresleni vlny /// class Vlna { // Vertex a index buffer object uint vboData; uint iboData; // Pocet trojuhelniku int triCount; /// /// Konstruktor, vytvori data /// /// Pocet vzorku v jedne ose public Vlna(uint n) { // Vytvoreni pole vrcholu obsahujicich pozici, normalu a barvu PositionNormalColor[] vertex = new PositionNormalColor[n * n]; // Naplneni pole vrcholu pozici a barvou. Normalu musime nechat na pozdeji, az budeme znat sousedy for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { double sx = (i - n / 2.0) / n * Math.PI * 2; sx *= sx; double sy = (j - n / 2.0) / n * Math.PI * 2; sy *= sy; float height = (float)(Math.Sin(sx + sy) * (n / 30.0)); vertex[i * n + j] = new PositionNormalColor(j, height, i, 0, 0, 0, 1, 0, 0); vertex[i * n + j].color = ComputeColor(height / (n / 30.0)); } } // Vytvoreni trojuhelnikove site triCount = (int)(3 * (n - 1) * (n - 1) * 2); uint[] index = new uint[triCount]; int p = 0; for (uint i = 0; i < n - 1; i++) { for (uint j = 0; j < n - 1; j++) { index[p++] = i * n + j; index[p++] = (i + 1) * n + j; index[p++] = i * n + j + 1; index[p++] = i * n + j + 1; index[p++] = (i + 1) * n + j; index[p++] = (i + 1) * n + j + 1; } } // Vypocet normal ComputeNormals(vertex, index); // Priprava vbo vboData = gl.GenBuffer(); gl.BindBuffer(GL.ARRAY_BUFFER, vboData); gl.BufferData(GL.ARRAY_BUFFER, (int)(n * n) * PositionNormalColor.SizeInBytes, vertex, GL.STATIC_DRAW); gl.BindBuffer(GL.ARRAY_BUFFER, 0); // Priiprava ibo iboData = gl.GenBuffer(); gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, iboData); gl.BufferData(GL.ELEMENT_ARRAY_BUFFER, index.Length * sizeof(uint), index, GL.STATIC_DRAW); gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, 0); gl.BindBuffer(GL.ARRAY_BUFFER, 0); } /// /// Vypocet barvicek na zaklade vysky /// /// Vyska z intervalu [-1;1] /// Interpolovana barva Vector3 ComputeColor(double param) { Vector3 low = new Vector3(0, 0.5f, 1); Vector3 mid = new Vector3(.9f, .8f, 0); Vector3 hig = new Vector3(.2f, .7f, 0); Vector3 res = new Vector3(); if (param < 0) { res = mid * (1 + (float)param) - low * (float)param; } else { res = mid * (1 - (float)(param)) + hig * (float)(param); } return res; } /// /// Vypocet normal /// /// Pole vrcholu /// Indexy trojuhelniku void ComputeNormals(PositionNormalColor[] vertex, uint[] index) { // Projit kazdy trojuhelnik (sklada se ze 3 vrcholu) for (int i = 0; i < index.Length; i += 3) { // Zjisit vektor od vrcholu 0 k 1 Vector3 v1 = vertex[index[i + 1]].position - vertex[index[i]].position; // Zjisit vektor od vrcholu 0 k 2 Vector3 v2 = vertex[index[i + 2]].position - vertex[index[i]].position; // Vektorovy soucin urci kolmy vektor Vector3 n = Vector3.Cross(v1, v2); n.Normalize(); // K normale kazdeho vrcholu pricist spocitanou normalu vertex[index[i]].normal += n; vertex[index[i + 1]].normal += n; vertex[index[i + 2]].normal += n; } // Normaly normalizovat! Ve vypoctu osvetleni se na to spoleha // Lze obejit povoleni glEnable(GL_NORMALIZE), pocita se vsak v kazdem snimku a brzdi vykreslovani for (int i = 0; i < vertex.Length; i++) { vertex[i].normal.Normalize(); } } public void Render() { // Vykresleni dat gl.BindBuffer(GL.ARRAY_BUFFER, vboData); gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, iboData); gl.EnableClientState(GL.VERTEX_ARRAY); gl.VertexPointer(3, GL.FLOAT, PositionNormalColor.SizeInBytes, (IntPtr)0); gl.EnableClientState(GL.NORMAL_ARRAY); gl.NormalPointer(GL.FLOAT, PositionNormalColor.SizeInBytes, (IntPtr)12); gl.EnableClientState(GL.COLOR_ARRAY); gl.ColorPointer(3, GL.FLOAT, PositionNormalColor.SizeInBytes, (IntPtr)24); gl.DrawElements(GL.TRIANGLES, triCount, GL.UNSIGNED_INT, (IntPtr)0); gl.DisableClientState(GL.VERTEX_ARRAY); gl.DisableClientState(GL.NORMAL_ARRAY); gl.DisableClientState(GL.COLOR_ARRAY); gl.BindBuffer(GL.ARRAY_BUFFER, 0); gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, 0); } } /// /// Struktura vrcholu obsahujci pozici, normalu a barvu /// [StructLayout(LayoutKind.Sequential)] struct PositionNormalColor { public Vector3 position; public Vector3 normal; public Vector3 color; /// /// Konstruktor z floatu /// /// X /// Y /// Z /// nX /// nY /// nZ /// R /// G /// B public PositionNormalColor(float x, float y, float z, float nx, float ny, float nz, float r, float g, float b) { position = new Vector3(x, y, z); normal = new Vector3(nx, ny, nz); color = new Vector3(r, g, b); } /// /// Velikost struktury v bytech /// public static int SizeInBytes { get { return Marshal.SizeOf(typeof(PositionNormalColor)); } } } }