You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
thebookofshaders/02/README-gr.md

9.2 KiB

Hello World

Συνήθως το παράδειγμα "Hello world!" είναι το πρώτο βήμα για να μάθει κανείς μια νέα γλώσσα. Είναι ένα απλό πρόγραμμα της μιας γραμμής που τυπώνει ένα ενθουσιώδες καλοσώρισμα και αναγέλλει τις δυνατότητες που μας περιμένουν.

Στη χώρα της GPU, ο σχεδιασμός χαρακτήρων είναι μια υπερβολικά περίπλοκη εργασία για πρώτο βήμα, οπότε θα προτιμήσουμε ένα φωτεινό φιλόξενο χρώμα για να διακυρήξουμε τον ενθουσιασμό μας!

Αμ διαβάζετε αυτό το κείμενο σε browser, το προηγούμενο τμήμα κώδικα είναι διαδραστικό. Αυτό σημαίνει πως μπορείτε να κάνετε κλικ και να αλλάξετε όποιο μέρος του κώδικα θέλετε να εξερευνήσετε. Οι αλλαγές θα γίνουν άμεσα ορατές χάρη στην αρχιτεκτονική της GPU που μεταγλωττίζει (compiles) και αντικαθιστά τους shaders "στον αέρα". Κάντε μια δοκιμή να αλλάξετε τις τιμές στη γραμμή 8.

Αν και αυτές οι απλές γραμμές κώδικα δε δείχνουν τίποτα σπουδαίο, μπορούμε να εξάγουμε σημαντικές γνώσεις από αυτές:

  1. Η γλώσσα των shaders έχει μια μοναδική συνάρτηση main που επιστρέφει ένα χρώμα στο τέλος, παρόμοια με τη C.

  2. Το τελικό χρώμα του pixel ανατίθεται (γράφεται) στην δεσμευμένη (reserved) καθολική μεταβλητή gl_FragColor.

  3. Αυτή η παρόμοια-με-C γλώσσα έχει ενσωματωμένες μεταβλητές (όπως η gl_FragColor), συναρτήσεις και τύπους. Σε αυτό το παράδειγμα συστηθήκαμε μόνο με το vec4 που αντιπροσωπεύει ένα διάνυσμα 4 διαστάσεων και ακρίβειας τύπου μονής κινητής υποδιαστολής (float). Αργότερα θα δούμε και άλλους τύπους όπως vec3 και vec2 όπως και τους γνωστούς: float, int και bool.

  4. Αν παρατηρήσουμε τον τύπο vec4 μπορούμε να συμπεράνουμε οτι τα τέσσερα μέρη αντιστοιχούν στα κανάλια χρώματος RED, GREEN, BLUE και ALPHA. Επίσης μπορούμε να δούμε πως οι τιμές τους είναι κανονικοποιημένες, που σημαίνει πως το εύρος τους είναι από 0.0 ως 1.0. Αργότερα θα δούμε πως η κανονικοποίηση των τιμών μας διευκολύνει στο να αντιστοιχίζουμε τιμές ανάμεσα σε μεταβλητές.

  5. Άλλο ένα σημαντικό χαρακτηριστικό σαν της C που βλέπουμε σε αυτό το παράδειγμα είναι η ύπαρξη preprocessor macros (μακροεντολών προεπεξεργαστή). Οι macros είναι μέρος ενός βήματος προ-μεταγλώττισης. Με αυτές μπορούμε να ορίσουμε (#define) καθολικές μεταβλητές και να κάνουμε κάποιες βασικές επιλογές υπό συνθήκη (conditional operations - με #ifdef και #endif). Όλες οι μακροεντολές ξεκινάνε με ένα hashtag (#). Η προ-μεταγλώττιση συμβαίνει ακριβώς πριν τη μεταγλώττιση, και αντιγράφει όλες τις κλήσεις σε #defines και ελέγχει τις συνθήκες #ifdef (κάτι είναι ορισμένο) και #ifndef (κάτι δεν είναι ορισμένο). Στο "hello world!" παράδειγμά μας παραπάνω, προσθέσαμε μόνο τη γραμμή 2 (αν έχει οριστεί η GL_ES), το οποίο κυρίως συμβαίνει όταν ο κώδικας μεταγλωττίζεται σε φορητές συσκευές και browsers.

  6. Οι τύποι κινητής υποδιαστολής είναι απαραίτητοι στους shaders, οπότε και το επίπεδο ακρίβειας είναι καίριο. Χαμηλότερη ακρίβεια σημαίνει γρηγορότερη απεικόνιση (rendering), αλλάμ με κόστος σε ποιότητα. Μπορείτε να είστε επιλεκτικοί και να προσδιορίσετε την ακρίβεια σε κάθε μεταβλητή που χρησιμοποιεί κινητή υποδιαστολή. Στη δεύτερη γραμμή (precision mediump float;) θέτουμε όλους τους floats σε μέση ακρίβεια. Μπορούμε επίσης να αποφασίσουμε να τους θέσουμε σε χαμηλή (precision lowp float;) ή υψηλή (precision highp float;).

  7. Η τελευταία, και ίσως πιο σημαντική λεπτομέρεια είναι πως το πρότυπο της GLSL δεν εγγυάται πως όλες οι μεταβλητές μετατρέπονται αυτόματα. Τι σημαίνει αυτό; Οι κατασκευαστές έχουν διαφορετικές προσεγγίσεις στο να επιταχύνουν τις διεργασίες των καρτών γραφικών, αλλά είναι υποχρεωμένοι να εγγυηθούν κάποιες ελάχιστες προδιαγραφές. Η αυτόματη μετατροπή δεν είναι μια απο αυτές. Στο “hello world!” παράδειγμά μας, το vec4 έχει ακρίβεια float (μονής κινητής υποδιαστολής), οπότε περιμένει να του αναθέσουμε float τιμές. Αν θέλετε να έχετε καλό και σταθερό κώδικα αντί να ξοδεύετε ώρες προσπαθώντας να διορθώσετε (debug) λευκές οθόνες, συνηθίστε να βάζετε την υποδιαστολή (.) στους floats σας. Κώδικας σαν κι αυτόν δε δουλεύει πάντα σωστα:

void main() {
    gl_FragColor = vec4(1,0,0,1);	// ERROR
}

Τώρα που περιγράψαμε τα πιο απαραίτητα στοιχεία του "hello world!" προγράμματός μας, ώρα να κάνετε κλικ στο τμήμα κώδικα και να αρχίσετε να δοκιμάζετε όλα όσα μάθαμε. Θα διαπιστώσετε πως σε περίπτωση λαθών το πρόγραμμα δεν θα μεταγλωττιστεί, και θα δείξει μια λευκή οθόνη. Υπάρχουν μερικά πράγματα να δοκιμάσετε, για παράδειγμα:

  • Δοκιμάστε να αντικαταστήσετε τους float με integers, η κάρτα γραφικών σας ίσως να μην ανεχτεί αυτή τη συμπεριφορά!

  • Δοκιμάστε να βάλετε σε σχόλια τη γραμμή 8 και να μη δώσετε τιμή για το pixel στη συνάρτηση

  • Δοκιμάστε να φτιάξετε μια ξεχωριστή συνάρτηση που επιστρέφει ένα συγκεκριμένο χρώμα και να την καλέσετε μέσα στη main(). Σα βοήθημα, αυτός είναι ο κώδικας μιας συνάρτησης που επιστρέφει κόκκινο:

vec4 red(){
    return vec4(1.0,0.0,0.0,1.0);
}
  • Υπάρχουν διάφοροι τρόποι για να αρχικοποιήσετε τυπους vec4, δοκιμάστε να ανακαλύψετε και άλλους. Ο ακόλουθος είνα ένας από αυτούς:
vec4 color = vec4(vec3(1.0,0.0,1.0),1.0);

Αν και αυτό το παράδειγμα δεν είναι ιδιαίτερα ενδιαφέρον, είναι το πιο βασικό - αλλάζουμε όλα τα pixels μέσα στον καμβά (για την ακρίβεια στο canvas element) στο ίδιο ακριβώς χρώμα. Στο επόμενο κεφάλαιο θα δούμε πως να αλλάζουμε το χρώμα κάθε pixel χρησιμοποιώντας δύο τύπους εισόδου: το χώρο (τη θέση του pixel στην οθόνη) και το χρόνο (τον αριθμό των δευτερολέπτων από τη στιγμή που φορτώθηκε η σελιδα).