Απόδοση 3D σκηνών - Κινούµενα γραφικά
Περιεχόµενα ενότητας
•Καταστολή κρυµµένων επιφανειών - Αλγόριθµος z-buffer •Τρισδιάστατες επιφάνειες: Κύβος – Σφαίρα – Κώνος - Κύλινδρος - Κυκλικός δίσκος – ∆ακτύλιος – Τοµέας δίσκου – Τοµέας δακτυλίου – Τόρος •Μίξη χρωµάτων – ∆ιαφάνεια •Κινούµενα γραφικά - ∆ιπλή ενταµίευση
Καταστολή κρυµµένων επιφανειών •Προφανής κανόνας 3D σχεδίασης: οι επιφάνειες που βρίσκονται πλησιέστερα στον παρατηρητή καλύπτουν τις επιφάνειες που βρίσκονται από πίσω τους •Ωστόσο, η OpenGL, εξ' αρχής δε λαµβάνει υπόψη την πληροφορία βάθους •Εάν σχεδιαστούν δύο επιφάνειες σε διαφορετικό βάθος µε επικαλυπτόµενες προβολές, µια επιφάνεια που βρίσκεται µακρύτερα από τον θεατή ίσως καλύψει µία κοντινότερη επιφάνεια (ανεπιθύµητη συµπεριφορά) •Η δήλωση των σχηµάτων µε τη σειρά, από το πιο αποµακρυσµένο προς το πλησιέστερο, δεν αποτελεί λύση.
Ενταµιευτής βάθους (z-buffer) •Ενταµιευτής βάθους: µητρώο µε διαστάσεις ίδιες µε τις διαστάσεις της επιφάνειας σχεδίασης σε pixels. •Κάθε στοιχείο του ενταµιευτή βάθους έχει ως τιµή τη συντεταγµένη z της πλησιέστερης επιφανείας στο επίπεδο του παρατηρητή στο εκάστοτε pixel.
•Τα µακρινότερα σηµεία (µακρινό επιπέδου αποκοπής) έχουν τιµή βάθους z=1 και τα πιο κοντινά σηµεία (εγγύς επίπεδο αποκοπής) έχουν τιµή βάθους z=0.
Ενεργοποίηση αλγορίθµου z-buffer α) ∆ηλώνουµε στην glutInitDisplayMode τη χρήση ενταµιευτή βάθους. glutInitDisplayMode(GL_DEPTH); β)Ενεργοποιούµε τη χρήσης του z-buffer glEnable(GL_DEPTH_TEST); γ) Στη συνάρτηση display (πριν το σχεδιασµό ή επανασχεδιασµό ενός καρέ), αρχικοποιούµε τον ενταµιευτή τιµών βάθους µε την εντολή glClear. glClear(GL_DEPTH_BUFFER_BIT); Η αρχικοποίηση του depth buffer θέτει ως προκαθορισµένη τιµή στα στοιχεία του τη µονάδα (τη µέγιστη τιµή βάθους των κανονικοποιηµένων συντεταγµένων) Αλλαγή αρχικής τιµής: glClearDepth(maxDepth); maxDepth: η µέγιστη τιµή βάθους (χρησιµοποιείται κατά τον καθαρισµό του ενταµιευτή βάθους)
Τρισδιάστατες επιφάνειες •Οι βιβλιοθήκες τις OpenGL ορίζουν εντολές µε τις οποίες µπορούµε να σχεδιάσουµε µε εύκολο τρόπο τρισδιάστατες επιφάνειες. •Αρκεί να δώσουµε χαρακτηριστικές παραµέτρους των επιφανειών (π.χ. ακτίνα σφαίρας ή µήκος έδρας κύβου) •Οι περισσότερες 3∆ επιφάνειες ανήκουν στην κατηγορία των τετραγωνικών επιφανειών (quadrics). Περιγράφονται από εξισώσεις 2ου βαθµού. ∆ύο κατηγορίες: α) Εντολές της βιβλιοθήκης GLUT β) Εντολές της βιβλιοθήκης GLU
Εντολές 3D επιφανειών της βιβλιοθήκης GLUT
•Οι εντολές 3D επιφανειών της GLUT έχουν δύο παραλλαγές. glutWire*: Eµφανίζουν το περίγραµµα των πολυγώνων που προσεγγίζουν την επιφάνεια (wireframe).
glutSolid*: Σχεδιάζουν τις επιφάνειες συµπαγείς.
Εντολές 3D επιφανειών της βιβλιοθήκης GLU •Έχουν πιο πολύπλοκη σύνταξη σε σχέση µε τις εντολές της GLUT, ωστόσο υποστηρίζουν περισσότερες δυνατότητες (πχ απόδοση υφής) •Κάθε επιφάνεια χαρακτηρίζεται προγραµµατιστικά ως ένα αντικείµενο της κλάσης GLUquadric •Η δηµιουργία κάθε νέας επιφανείας απαιτεί την αρχικοποίηση ενός νέου αντικειµένου GLUquadric *qObj. •Αρχικοποίηση του αντικειµένου qObj γίνεται µε την εντολή gluNewQuadric GLUquadric * gluNewQuadric( ); (Επιστρέφει δείκτη σε αντικείµενο της κλάσης GLUquadric) Σύνταξη αρχικοποίησης qObj = gluNewQuadric( ); •Αποδίδουµε στο αντικείµενο qObj µια συγκεκριµένη επιφάνεια χρησιµοποιώντας εντολές της GLU (αναλύονται στη συνέχεια). Για να διαγράψουµε ένα αντικείµενο χρησιµοποιούµε την εντολή gluDeleteQuadric: void GLUdeleteQuadric( GLUquadric *quadObject );
Εντολές 3D επιφανειών της βιβλιοθήκης GLU •Έχουµε τη δυνατότητα να αναπαραστήσουµε τις τρισδιάστατες επιφάνειες είτε συµπαγείς είτε µε τη µορφή πλέγµατος είτε σχεδιάζοντας µόνο τα σηµεία των κορυφών. void gluQuadricDrawStyle(GLUquadric *quadObject, GLenum drawStyle); quadObject δείκτης στο αντικείµενο της επιφανείας για την οποία καθορίζουµε τον τρόπο αναπαράστασης drawStyle: δέχεται τις συµβολικές σταθερές: GLU_POINT: Σχεδιάζονται µόνο οι κορυφές των επιφανειών GLU_LINE: Σχεδιάζεται το πλέγµα της επιφανείας GLU_FILL: Οι επιφάνειες του αντικειµένου σχεδιάζονται συµπαγείς.
Κύβος void glutWireCube ( GLdouble edgeLength ); για τη σχεδίαση του περιγράµµατος κύβου void glutSolidCube ( GLdouble edgeLength ); για τη σχεδίαση συµπαγούς κυβικού σχήµατος, edgeLength: το µήκος των ακµών
•O κύβος σχεδιάζεται µε το κέντρο του στην αρχή του συστήµατος συντεταγµένων (0,0,0) και µε τις έδρες του παράλληλες προς τα επίπεδα ΧΥ ΧΖ και ΥΖ του συστήµατος συντεταγµένων σκηνής. •Σχεδίαση του κύβου µε διαφορετικό προσανατολισµό απαιτεί ένα µετασχηµατισµό µοντέλου.
Σφαίρα void glutWireSphere( GLdoule radius, GLint slices, GLint stacks ); για τη σχεδίαση σφαιρικού πλέγµατος void glutSolidSphere( GLdoule radius, GLint slices, GLint stacks ); για τη σχεδιάση µιας συµπαγούς σφαιρικής επιφανείας. radius: η ακτίνα της σφαίρας slices: το πλήθος των οριζοντίων υποδιαιρέσεων (µεσηµβρινοί) stacks: το πλήθος των κατακόρυφων υποδιαιρέσεων (γεωγραφικά πλάτη) •Το κέντρο της σφαίρας τοποθετείται στην αρχή του καρτεσιανού συστήµατος συντεταγµένων σκηνής. •Οι πόλοι της σφαίρας τοποθετούνται επί του άξονα z (στα σηµεία z=r και z=-r)
Κώνος glutWireCone(GLdouble base, GLdouble height, GLint slices, Glint stacks); για τη σχεδίαση κωνικού περιγράµµατος και την εντολή glutSolidCone (GLdouble base, GLdouble height, GLint slices, Glint stacks); για τη σχεδιάση συµπαγούς κωνικής επιφανείας base: η ακτίνα της βάσης του κώνου height: το ύψος του κώνου slices: το πλήθος των οριζοντίων υποδιαιρέσεων (“φέτες”) stacks: το πλήθος των κατακόρυφων υποδιαιρέσεων •To κέντρο της βάσης του κώνου τοποθετείται στην αρχή του συστήµατος συντεταγµένων σκηνής. •Ο άξονας του κώνου ακολουθεί το θετικό ηµιάξονα Oz.
Κύλινδρος
gluCylinder(GLUquadric *qObj, GLdouble baseRadius, GLdouble topRadius, GLdouble height, GLdouble slices, GLdouble stacks); qObj: δείκτης στο αντικείµενο της κυλινδρικής επιφάνειας baseRadius, topRadius: οι ακτίνες της βάσης και της κορυφής του κυλίνδρου height: το ύψος του κυλίνδου slices, stacks: το πλήθος των οριζοντίων και κάθετων υποδαιρέσεων •Ο κύλινδρος σχεδιάζεται µε τη βάση του στο επίπεδο XY και εκτείνεται προς τον θετικό ηµιάξονα Oz.
Κυκλικός δίσκος - ∆ακτύλιος
void gluDisk (GLUquadric *quadObject, GLdouble innerRadius, GLdouble outerRadius, Glint slices, Glint loops ); quadObject: το αντικείµενο στο οποίο αντιστοιχίζουµε την επιφάνεια innerRadius: η εσωτερική ακτίνα από την οποία ξεκινάει ο σχηµατισµός του δακτυλίου. Για innerRadius=0 σχεδιάζουµε κυκλικό δίσκο outerRadius: η εξωτερική ακτίνα του δίσκου ή δακτυλίου slices: το πλήθος των γωνιακών υποδιαιρέσεων loops: το πλήθος των ακτινικών υποδιαιρέσεων •Σχεδίαση επί του επιπέδου XY µε το κέντρο στην αρχή των αξόνων.
Κυκλικός τοµέας – Τοµέας δακτυλίου
gluPartialDisk (GLUquadric *qObj, GLdouble innerRadus, GLdouble outerRadius, GLdouble slices, GLdouble loops, GLdouble startAngle, GLdouble sweepAngle); startAngle: η γωνία από την οποία ξεκινάει ο σχεδιασµός του σχήµατος sweepAngle: το γωνιακό εύρος του δακτυλίου •Η γωνιακή θέση 0 αντιστοιχεί στην κατεύθυνση προς τα πάνω. •H τιµή της γωνιακής θέσης αυξάνεται κατά την αρνητική φορά. •Σχεδίαση επί του επιπέδου X-Y µε το κέντρο στην αρχή των αξόνων.
Τόρος
void glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); void glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); innerRadius: εκφράζει την ακτίνα της κυκλικής διατοµής του τόρου outerRadius: η απόσταση του κέντρου της διατοµής του τόρου από τον άξονά του sides: το πλήθος των υποδιαιρέσεων που προσεγγίζουν την περιφέρεια µιας κυκλικής διατοµής του τόρου rings: το πλήθος των κυκλικών διατοµών που χρησιµοποιούµε για την προσέγγιση του τόρου •Ο τόρος σχεδιάζεται θεωρώντας ως άξονά του τον Oz και κέντρο του την αρχή του συστήµατος συντεταγµένων.
Μίξη χρωµάτων
•Στην περίπτωση επικαλυπτόµενων σχηµάτων έχουµε τη δυνατότητα να αναµίξουµε τις χρωµατικές τιµές τους και να παραγάγουµε έναν ενδιάµεσο χρωµατισµό στα κοινά σηµεία τους •Μπορούµε να προσoµοιώσουµε διαφανείς ή ηµιδιαφανείς επιφάνειες. •Για τη µίξη χρωµάτων συνήθως χρησιµοποιούνται το χρωµατικό µοντέλο RGBA. (Τρεις χρωµατικές συνιστώσες και η συνιστώσα alpha, η οποία χρησιµοποιείται ως συντελεστής µίξης)
Στρώµατα στη µίξη χρωµάτων
•Στην OpenGL, για να εκτελέσουµε µίξη χρωµάτων ορίζουµε τα στρώµατα Στη µίξη χρωµάτων ορίζουµε δύο στρώµατα: α) Στρώµα προορισµού (destination): Περιέχει τις ήδη υπάρχουσες χρωµατικές τιµές του ενταµιευτή χρωµατικών τιµών δηλαδή •το χρώµα φόντου •ή το χρώµα του τελευταίου αντικειµένου που σχεδιάστηκε •ή συνδυασµός των παραπάνω, εάν προηγήθηκε µίξη χρωµάτων β) Στρώµα πηγής (source): Περιέχει τις χρωµατικές τιµές των σχηµάτων που θα υπερθέσουµε στον προορισµό.
Συντελεστές µίξης Συντελεστές µίξης: αποδίδονται στο στρώµα προορισµού και στο στρώµα πηγής Καθορίζουν σε τι ποσοστό θα συµµετάσχουν οι χρωµατικές τιµές του προορισµού και της πηγής κατά την υπέρθεσή τους. ∆ιαδικασία µίξης: α) Κάθε εντολή δήλωσης σχήµατος αποθηκεύει την περιγραφή του σε ένα κενό στρώµα πηγής. β) Εκτελείται η µίξη στρώµατος πηγής - στρώµατος προορισµού γ) Παράγουµε ένα ανανεωµένο στρώµα προορισµού. •Η διαδικασία µίξης εκτελείται επαναληπτικά.
(Rs , Gs , Bs , As )
Συντελεστές µίξης Συντελεστές µίξης στρώµατος προορισµού
D = (Dr , D g , Db , Da )
Συντελεστές µίξης στρώµατος πηγής
S = (S r , S g , S b , S a )
Αποθηκευµένη χρώµα στο στρώµα προορισµού
(Rd , Gd , Bd , Ad )
Τρέχον χρώµα στο στρώµα πηγής
(Rs , Gs , Bs , As )
Νέο χρώµα στρώµατος προορισµού
(S
r
⋅ Rs + Dr ⋅ Rd ,
S g ⋅ G s + D g ⋅ Gd ,
S b ⋅ Bs + Db ⋅ Bd ,
S a ⋅ As + Da ⋅ Ad )
Ρύθµιση µίξης χρωµάτων
Ενεργοποιούµε τη λειτουργία µίξης χρωµάτων µε την εντολή: glEnable(GL_BLEND); Απόδοση συντελεστών µίξης σε κάθε στρώµα: void glBlendFunc( GLenum sFactor, GLenum dFactor); sFactor, dFactor: συµβολικές σταθερές που καθορίζουν τους συντελεστές µίξης για το στρώµα πηγής και το στρώµα προορισµού αντίστοιχα
Παράµετροι ρύθµισης συντελεστών µίξης sFactor και dFactor: ∆έχονται τις εξής σταθερές: GL_ZERO: Θέτει τους συντελεστές µίξης (0,0,0,0) για το εκάστοτε στρώµα. GL_ONE: Ορίζει τους συντελεστές µίξης (1,1,1,1) για το εκάστοτε στρώµα. GL_SRC_ALPHA: Επιλέγουµε για συντελεστές µίξης του εκάστοτε στρώµατος, τη συνιστώσα alpha του χρώµατος στο στρώµα πηγής. (Αs,As,As,As) (µοντέλο RGBA) GL_DST_ALPHA: Επιλέγουµε ως συντελεστή µίξης για το εκάστοτε στρώµα τη συνιστώσα alpha του χρώµατος στο στρώµα προορισµού. (Ad,Ad,Ad,Ad) (µοντέλο RGBA) GL_ONE_MINUS_SRC_ALPHA: Επιλέγουµε ως συντελεστή µίξης για το εκάστοτε στρώµα το συµπλήρωµα της συνιστώσας As ως προς τη µονάδα . (1-As,1-As,1-As,1-As) (µοντέλο RGBA) GL_ONE_MINUS_DST_ALPHA: Επιλέγουµε ως συντελεστή µίξης για το εκάστοτε στρώµα το συµπλήρωµα της συνιστώσας Ad ως προς τη µονάδα. (1-Ad,1-Ad,1-Ad,1-Ad) (µοντέλο RGBA) Η προκαθορισµένη τιµή για την παράµετρο sFactor είναι GL_ONE και για την για παράµετρο dFactor GL_ZERO. (Το χρώµα πηγής επικαλύπτει το χρώµα προορισµού).
Μοντελοποίηση διαφάνειας •Η διαφάνεια µιας επιφάνειας καθορίζεται ορίζοντας την alpha συνιστώσα της. •Ορίζουµε µια επιφάνεια ως πλήρως διαφανή µε τιµή alpha=1 και ως πλήρως αδιαφανή µε τιµή alpha=0. Τρόπος µίξης χρωµάτων στην απόδοση διαφάνειας: glBlendFunc(GL_ONE_MINUS_SRC_ALPHA,GL_SRC_ALPHA); Απαιτείται η χρήση του χρωµατικού µοντέλου RGBA: glutInitDisplayMode(GLUT_RGBA);
Κινούµενα γραφικά
•H δηµιουργία κινούµενων γραφικών είναι εφικτή µεταβάλλοντας το σκηνικό και δίνοντας διαδοχικές εντολές επανασχεδιασµού της σκηνής. •Η διαρκής ανανέωση και επενασχεδιασµός καρέ χωρίς περαιτέρω µέριµνα εξάγει κινούµενα γραφικά χαµηλής ποιότητας λόγω τρεµοπαίγµατος (flickering). •Αιτία: οι ασύγχρονες διεργασίες εγγραφής και ανάγνωσης του ενταµιευτή χρωµατικών τιµών
Απλή ενταµίευση (single buffering)
α) Το τρέχον καρέ προωθείται στον ditital-to-analog µετατροπέα της οθόνης (DAC). β) Η µηχανή της OpenGL, εγγράφει τις χρωµατικές τιµές του επόµενου καρέ στον ίδιο ενταµιευτή. Οι δύο παραπάνω διαδικασίες δεν είναι συγχρονισµένες (Οι τιµές του color buffer ενδέχεται να τροποποιηθούν ενώ ο DAC της οθόνης ανακτά το πρώτο καρέ).
∆ιπλή ενταµίευση (double buffering)
Εφαρµογή διπλής ενταµίευσης α) ∆ηλώνουµε τη χρήση διπλής ενταµίευσης στην glutInitDisplayMode: glutInitDisplayMode(GLUT_DOUBLE); β) Στο τέλος της συνάρτησης display, εναλάσσουµε τους ενταµιευτές προσκηνίου και παρασκηνίου µε την εντολή glutSwapBuffers. void glutSwapBuffers(); •Όταν χρησιµοποιούµε την εντολή glutSwapBuffers, δεν είναι αναγκαία η εκτέλεση της glFlush.
Τέλος ενότητας