Computer graphics/2014-2015/Laborator 3

From Wikiversity
Jump to navigation Jump to search

Linkuri Rapide: Prima Pagină; Laboratoare agenda, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, JOGL template.


JOGL (Partea 2)[edit]

NOTĂ: Codul pentru crearae unei ferestre de randare se poate găsii la: Grafica -- 2014-2015 -- info.uvt.ro/JOGL-Template

Antialising[edit]

Aliasing este un efect introdus din cauza discretizării imaginilor care provoacă semnalele continue să devină imperceptibile.



Există mai multe tehnici de antialiasing în cadru JOGL:

  • Color blending -- două culori pot fi amestecate folosind diferite criterii. Următorul exemplu arată cum putem obtine un efect de tipul antialising:
	[...]

	public void init(GLAutoDrawable canvas)
	{

		[...]

		// Activate the GL_LINE_SMOOTH state variable. Other options include 
		// GL_POINT_SMOOTH and GL_POLYGON_SMOOTH.
		gl.glEnable(GL.GL_LINE_SMOOTH);

		// Activate the GL_BLEND state variable. Means activating blending.
		gl.glEnable(GL.GL_BLEND);

		// Set the blend function. For antialiasing it is set to GL_SRC_ALPHA for the source
		// and GL_ONE_MINUS_SRC_ALPHA for the destination pixel.
		gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);

		// Control GL_LINE_SMOOTH_HINT by applying the GL_DONT_CARE behavior. 
		// Other behaviours include GL_FASTEST or GL_NICEST.
		gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_DONT_CARE);
		// Uncomment the following two lines in case of polygon antialiasing
		//gl.glEnable(GL.GL_POLYGON_SMOOTH);
		//glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);

	}

	public void display(GLAutoDrawable canvas) {
		GL2 gl = canvas.getGL().getGL2();

		[...]
		
		gl.glLineWidth(1.5f);
	
		gl.glColor3f(1.f, 0.f, 0.f);
		gl.glBegin(GL2.GL_LINES);
			gl.glVertex2f(0.2f, 0.2f);
			gl.glVertex2f(0.9f, 0.9f);			
		gl.glEnd();
		
		gl.glColor3f(0.f, 1.f, 0.f);
		gl.glBegin(GL2.GL_LINES);
			gl.glVertex2f(0.9f, 0.2f);
			gl.glVertex2f(0.2f, 0.9f);
		gl.glEnd();
		[...]
	}

	[...]


Încercati să activați/deactivavți GL_BLEND și/sau GL_LINE_SMOOTH și observați diferențele.


  • Handling the accumulation buffer -- este cel mai simplu buffer din OpenGL, acesta are o singură funcție (metodă) numită glAccum. Este un extended-range color buffer care permite stocarea imaginilor/scenelor după randare. Este folosit pentru a crearea effectelor de tip antialiasing, motion blur, depth of field etc. Acestă metodă va fi detaliată în laboratoare ulterioare despre bufferele din OpenGL.
  • multisampling -- mai eficient decât prima tehnică dar nu poate să fie restricționată la nivel de subelemente dintr-o șcenă.

Link-uri Utile:

Poligoane[edit]

Sunt alcătuite dintr-o singur line loop.


Validitate[edit]

In JOGL doar poligoanele convexe sunt valide. Dacă dorim să desenăm poligoane concave trebuie să fie desenate linie cu linie folosind GL_LINE_LOOP. O altă posibilitate este de a împărții poligonul concav în mai multe poligoane convexe (tessallation, triangualtion).


Link-uri Utile:

Construirea poligoanelor[edit]

Poligoanele sunt compse din poligoane mai mici. Acestea pot fi triunghiuri (triangulation) sau poligoane mai mici (tessellation). Cel mai simplu poligon este triunghiul.


Dimensionalitatea[edit]

Poligoanele se pot afla pe același plan sau pe planuri diferite. Acest lucru depinde de definire nodurior care definesc poligonul.

Primitive[edit]

În JOGL putem crea poligoane prin interpretarea nodurilor:

  • polygons -- by using GL.GL_POLYGON
  • quads -- by using GL.GL_QUADS
    • quad strip -- by using GL.GL_QUAD_STRIP
  • triangles -- by using GL.GL_TRIANGLES
    • triangle strip -- by using GL.GL_TRIANGLE_STRIP
    • triangle fan -- by using GL.GL_TRIANGLE_FAN

Dreptunghiul (rectangle) se definește cu ajutorul funcției (metodei) glRect.


public class MainFrame
{
	[...]

	public void display(GLAutoDrawable canvas) {
		GL2 gl = canvas.getGL().getGL2();

		[...]

		gl.glBegin(GL2.GL_POLYGON);
			gl.glColor3f(1.f, 0.f, 0.f);
			gl.glVertex2f(0.2f, 0.2f);
			gl.glColor3f(0.f, 1.f, 0.f);
			gl.glVertex2f(0.2f, 0.4f);
			gl.glColor3f(0.f, 0.f, 1.f);
			gl.glVertex2f(0.4f, 0.4f);
			gl.glColor3f(1.f, 1.f, 1.f);
			gl.glVertex2f(0.4f, 0.2f);
		gl.glEnd();

		[...]
	}

	[...]
}

Link-uri Utile:

Umplerea și orientarea Poligoanelor[edit]

Poligoane JOGL pot fi umplute cu o culoare sau, sunt reprezentate doar de conturul definit de noduri. Funcția (metoda) care permite acest lucru este glPolygonMode(face, mode), unde faces poate avea valorile GL_FRONT, GL_BACK, GL_FRONT_AND_BACK și mode poate avea valorile GL_POINT, GL_LINE sau GL_FILL. Poligoanele se pot randa diferit pentru fiecare față definită.


O trăsătură importantă a poligoanelor este cea de a desena doar fața sau spatele acestora. Această acțiune este controlată prin glCullFace(face) unde face poate avea valorile GL_FRONT, GL_BACK, GL_FRONT_AND_BACK. Această prooprietate este numită culling și ajută la optimizarea aplicațiilor OpenGL.

Poligoanele pot avea nodurile specificate în ordine trigonometrică sunt considerate front-faced iar cele specificate în ordine inversă și sunt considerate back-faced. Aceast comportament poate fii schimbat folosind funcția (metoda) glFrontFace. Acesta permite doi parametrii: GL_CW (ClockWise) și GL_CCW (CounterClockWise - Trigonometric).


Următorul fragment de cod demonstrează umplerea și orientarea poligoanelor în JOGL:

public class MainFrame
{
	[...]

	public void display(GLAutoDrawable canvas) {
		GL2 gl = canvas.getGL().getGL2();

		[...]

		// Do not render front-faced polygons.
		gl.glCullFace(GL.GL_FRONT);
		// Culling must be enabled in order to work.
		gl.glEnable(GL.GL_CULL_FACE);		

		gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL);

		// Define vertices in clockwise order (back-faced)
		gl.glBegin(GL2.GL_POLYGON);
			gl.glColor3f(1.f, 0.f, 0.f);
			gl.glVertex2f(0.2f, 0.2f);
			gl.glColor3f(0.f, 1.f, 0.f);
			gl.glVertex2f(0.2f, 0.4f);
			gl.glColor3f(0.f, 0.f, 1.f);
			gl.glVertex2f(0.4f, 0.4f);
			gl.glColor3f(1.f, 1.f, 1.f);
			gl.glVertex2f(0.4f, 0.2f);
		gl.glEnd();

		[...]
	}

	[...]
}

while the next one will not:

public class MainFrame
{
	[...]

	public void display(GLAutoDrawable canvas) {
		GL2 gl = canvas.getGL().getGL2();

		[...]

		// Do not render back-faced polygons.
		gl.glCullFace(GL.GL_BACK);
		// Culling must be enabled in order to work.
		gl.glEnable(GL.GL_CULL_FACE);		

		gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL);

		// Define vertices in clockwise order (back-faced).
		gl.glBegin(GL2.GL_POLYGON);
			gl.glColor3f(1.f, 0.f, 0.f);
			gl.glVertex2f(0.2f, 0.2f);
			gl.glColor3f(0.f, 1.f, 0.f);
			gl.glVertex2f(0.2f, 0.4f);
			gl.glColor3f(0.f, 0.f, 1.f);
			gl.glVertex2f(0.4f, 0.4f);
			gl.glColor3f(1.f, 1.f, 1.f);
			gl.glVertex2f(0.4f, 0.2f);
		gl.glEnd();

		[...]
	}

	[...]
}

Poligon stipple[edit]

Poligoanele pot fi umplute cu un pattern numitul sipple pattern (hașurat) folosind funcția (metoda) glPolygonStipple :


public class MainFrame
{

	[...]
	byte mask[] = {
        	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	        0x03, (byte)0x80, 0x01, (byte)0xC0, 0x06, (byte)0xC0, 0x03, 0x60, 

	        0x04, 0x60, 0x06, 0x20, 0x04, 0x30, 0x0C, 0x20, 
	        0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20,
	        0x04, 0x06, 0x60, 0x20, 0x44, 0x03, (byte)0xC0, 0x22, 
	        0x44, 0x01, (byte)0x80, 0x22, 0x44, 0x01, (byte)0x80, 0x22, 
	        0x44, 0x01, (byte)0x80, 0x22, 0x44, 0x01, (byte)0x80, 0x22,
	        0x44, 0x01, (byte)0x80, 0x22, 0x44, 0x01, (byte)0x80, 0x22, 
	        0x66, 0x01, (byte)0x80, 0x66, 0x33, 0x01, (byte)0x80, (byte)0xCC, 

	        0x19, (byte)0x81, (byte)0x81, (byte)0x98, 0x0C, (byte)0xC1, (byte)0x83, 0x30,
	        0x07, (byte)0xe1, (byte)0x87, (byte)0xe0, 0x03, 0x3f, (byte)0xfc, (byte)0xc0, 
	        0x03, 0x31, (byte)0x8c, (byte)0xc0, 0x03, 0x33, (byte)0xcc, (byte)0xc0, 
	        0x06, 0x64, 0x26, 0x60, 0x0c, (byte)0xcc, 0x33, 0x30,
	        0x18, (byte)0xcc, 0x33, 0x18, 0x10, (byte)0xc4, 0x23, 0x08, 
	        0x10, 0x63, (byte)0xC6, 0x08, 0x10, 0x30, 0x0c, 0x08, 
	        0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08};

	public void display(GLAutoDrawable canvas) {
		GL2 gl = canvas.getGL().getGL2();

		gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL);

		// Set the polygon mask.
		gl.glPolygonStipple (mask, 0);
		// Enable polygon stipple.
		gl.glEnable (GL2.GL_POLYGON_STIPPLE);

		// Define vertices in clockwise order (back-faced).
		gl.glBegin(GL2.GL_POLYGON);
			gl.glColor3f(1.f, 0.f, 0.f);
			gl.glVertex2f(0.2f, 0.2f);
			gl.glColor3f(0.f, 1.f, 0.f);
			gl.glVertex2f(0.2f, 0.4f);
			gl.glColor3f(0.f, 0.f, 1.f);
			gl.glVertex2f(0.4f, 0.4f);
			gl.glColor3f(1.f, 1.f, 1.f);
			gl.glVertex2f(0.4f, 0.2f);
		gl.glEnd();

		// Disable polygon stipple.
		gl.glDisable (GL2.GL_POLYGON_STIPPLE);

		[...]
	}

	[...]
}

Normala[edit]

Normala este reprezentată de linii perpendiculare pe o suprafață. Acestea sunt importante pentru a reprezenta surse de lumină și efectele acestora asupra obiectele dintr-o scenă. Mai multe detalii în laboratorul care vorbim despre sursele de lumină dntr-o scenă.


O normală este specificată folosind funcțiile (metodele) din familia glNormal*(). Valorile argumentelor sun între [-1,1].


public class MainFrame
{
	[...]

	public void display(GLAutoDrawable canvas) {
		GL2 gl = canvas.getGL().getGL2();

		[...]

		// Do not render front-faced polygons.
		gl.glCullFace(GL.GL_FRONT);
		// Culling must be enabled in order to work.
		gl.glEnable(GL.GL_CULL_FACE);		

		gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL);

		// Define vertices in clockwise order (back-faced).
		gl.glBegin(GL2.GL_POLYGON);
			// Define normal for vertex 1
			gl.glNormal3f(0.f, 0.f, 1.f);
			gl.glColor3f(1.f, 0.f, 0.f);
			gl.glVertex2f(0.2f, 0.2f);

			// Define normal for vertex 2
			gl.glNormal3f(0.f, 0.f, 1.f);
			gl.glColor3f(0.f, 1.f, 0.f);
			gl.glVertex2f(0.2f, 0.4f);

			// Define normal for vertex 3
			gl.glNormal3f(0.f, 0.f, 1.f);
			gl.glColor3f(0.f, 0.f, 1.f);
			gl.glVertex2f(0.4f, 0.4f);

			// Define normal for vertex 4
			gl.glNormal3f(0.f, 0.f, 1.f);
			gl.glColor3f(1.f, 1.f, 1.f);
			gl.glVertex2f(0.4f, 0.2f);
		gl.glEnd();

		[...]
	}

	[...]
}


Introducere Bump mapping[edit]

Bump mapping este folosit pentru a crea iluzia de suprafață 3D pe o textură plată. Aceasta folosește definiția normalei în OpenGL.


Două tipuri de maps sunt folosite pentru bump mapping: bump și normal map. Ambele tipuri de map (texturi) pot crea iluzia umprelor pe o suprafață. Pentru a realiza această iluzie bump maps stochează și înălțimea fiecărui punct de pe o suprafață pe când normal maps stochează normalele unei suprafeței. Rezultatele obținute cu normal maps sunt mai netede decât cu bump maps.

Ideia este perturbarea normalelor astfel încât nodurile nu sunt iluminate uniform. Gradul de perturbație este dat de valoare bump pixel-ului (pentru bump map) sau valoarea normalei (pentru normal map).


Link-uri Utile:

Construirea unei liste de display -- Display Lists[edit]

Display lists pot fi văzute ca și funcții C care odată definite pot fi folosite de câte ori este nevoie. Acestea stochează o serie de comenzi OpenGL. Sunt utile din cauza performanței sporite. Comenzile OpenGL în aceste liste sunt precompilate astfel ele sunt stochate în memoria GPU.

ID-urile pentru display list sunt generate folosind glGenLists. Fiecare comandă pe care dorim să o stochăm într-un Display List trebuie inclusă într-un bloc de cod începând cu glNewList(int id, int mode) (unde mode poate avea valorile GL_COMPILE - crearea listei, sau GL_COMPILE_AND_EXECUTE - crearea listei compilarea și executarea listei). La final trebuie să fie glEndList.

public class MainFrame
{
	[...]

	int aCircle;

	public void init(GLAutoDrawable canvas)
	{

		[...]

		// Generate a unique ID for our list.
		aCircle = gl.glGenLists(1);

		// Generate the Display List
		gl.glNewList(aCircle, GL2.GL_COMPILE);
			drawCircle(gl, 0.5f, 0.5f, 0.4f);
		gl.glEndList();

	}

	int aCircle;

	public void display(GLAutoDrawable canvas) {
		GL2 gl = canvas.getGL().getGL2();

		[...]

		gl.glColor3f(1.0f, 1.0f, 1.0f);
		// Call the Display List i.e. call the commands stored in it.
		gl.glCallList(aCircle);

	}

	// Here we define the function for building a circle from line segments.
	private void drawCircle(GL gl, float xCenter, float yCenter, float radius) {

		double x,y, angle;

		gl.glBegin(GL2.GL_LINE_LOOP);
		for (int i=0; i<360; i++) {
			angle = Math.toRadians(i);
			x = radius * Math.cos(angle);
			y = radius * Math.sin(angle);
			gl.glVertex2d(xCenter + x, yCenter + y);
		}
		gl.glEnd();

	}
	[...]
}

Link-uri Utile:

API[edit]

Exerciții[edit]

  • Desenați o casă folosind GL_TRIANGLES, GL_POLYGON. Adăugați un cerc galben care (Opțional) se mișcă prin scenă de la dreapta la stânga. Umpleți fiecare secțiune a casei cu culori diferite. Folosiți Display Lists
  • Desenați o tablă de șah. NU este permisă umlerea poligoanelor cu culoarea neagră. Folosiți backface culling.
  • Opțional:Desenați fractalul Mandelbrot set. Puteți găsii algoritmul aici: http://en.wikipedia.org/wiki/Mandelbrot_set#For_programmers