Προγραμματισμός 3Δ αντικειμένων

Προγραμματισμός 3Δ αντικειμένων

Ένα ταχύρυθμο εργαστήριο εισαγωγής στην γλώσσα προγραμματισμού Processing και στον τρόπο με τον οποίο μπορούμε να προγραμματίσουμε τρισδιάστατα αντικείμενα. Όσοι από εσάς θέλετε να ασχοληθείτε περισσότερο ή να θυμηθείτε τα παλιά (μιλάω για τους βετεράνους του ομίλου) μπορείτε να δείτε τα μαθήματα που κάναμε τα προηγούμενα χρόνια στον όμιλο μέσα από την προσωπική μου σελίδα.

Ας αρχίσουμε με τα βασικά. Το πρώτο μας μέλημα είναι να δημιουργήσουμε έναν καμβά που θα έχει συγκεκριμένο μέγεθος και χρώμα. Για να ορίσουμε το μέγεθος χρησιμοποιούμε την εντολή size, η οποία χρειάζεται δυο αριθμούς, το πλάτος και το ύψος του καμβά σε pixel.

size(600,300);

Αν δεν ορίσω συγκεκριμένο χρώμα για το φόντο, η Processing επιλέγει αυτόματα το γκρι. Ας δοκιμάσουμε την εντολή background με τον αριθμό 0.

size(600,300);
background(0);

Τι χρώμα είναι το 0; Το μαύρο. Αν δοκιμάσετε το 255 αντί για το 0 τότε ο καμβάς θα γίνει άσπρος. Άρα χρησιμοποιώντας έναν αριθμό με την εντολή background μπορούμε να δημιουργήσουμε τις αποχρώσεις του γκρι.

Πάμε να βάλουμε τώρα λίγο χρώμα. Αν αντί για έναν αριθμό, βάλουμε τρεις στην background τότε αυτή θα δημιουργήσει ένα χρώμα αναμειγνύοντας το κόκκινο, το πράσινο και το μπλε. Ο πρώτος αριθμός είναι η φωτεινότητα του κόκκινου. ο δεύτερος του πράσινου και ο τρίτος του μπλε και όλα παίρνουν τιμές από 0 (σκοτεινό) μέχρι 255 (φωτεινό). Για να φτιάξουμε λοιπόν ένα έντονο ροζ φόντο.

size(600,300);
background(255,0,255);

Φτάνει με το φόντο… ας βάλουμε μέσα και ένα αντικείμενο, όπως έναν κύβο. Η εντολή για τον κύβο είναι η box και δέχεται έναν αριθμό που ορίζει το μέγεθος της κάθε πλευράς του κύβου σε pixel. Προσοχή όμως. Πριν την χρησιμοποιήσω, θα πρέπει να προσθέσω κάτι στην συνάρτηση size. Εκτός από τους 2 αριθμούς (πλάτος – ύψος καμβά) θα πρέπει να γράψω στο τέλος P3D για να δηλώσω ότι έχω πλέον τρισδιάστατο χώρο.

size(600,300,P3D);
background(70,0,140);
box(100);

Τι έγινε ακριβώς; Ο κύβος έχει τοποθετηθεί στην θέση 0,0 η οποία βρίσκεται στο πάνω αριστερό μέρος του καμβά. Για να τον τοποθετήσω στη μέση θα πρέπει αρχικά να μετακινηθώ εκεί. Χρησιμοποιώ την εντολή translate η οποία δέχεται 2 αριθμούς, πόσα pixel θα μετακινηθώ αριστερά (κατά πλάτος) και πόσα προς τα κάτω (κατά ύψος).

size(600,300,P3D);
background(70,0,140);
translate(300,150);
box(100);

Τώρα το έφερα στην μέση της οθόνης. Μπορώ άραγε να το μετακινήσω και πιο μπροστά ή πιο πίσω; Αφού είναι τρισδιάστατος πλέον ο χώρος μπορώ. Αν προσθέσω ακόμα έναν αριθμό στην translate τότε ορίζω πόσο θα μετακινηθεί κοντά ή μακριά από τα μάτια μου. Αν βάλω θετικό αριθμό θα έρθει πιο κοντά και αν βάλω αρνητικό θα μετακινηθεί προς το βάθος.

size(600,300,P3D);
background(70,0,140);
translate(300,150,-300);
box(100);

Προσοχή! Στο παραπάνω πρόγραμμα δεν έχω μικρύνει τον κύβο μου (παραμένει με διάσταση 100), απλά τον έστειλα 300 pixel προς το βάθος της οθόνης.

Η αλήθεια είναι βέβαια ότι τόση ώρα δεν μοιάζει και πολύ με κύβος αλλά με τετράγωνο. Αυτό συμβαίνει γιατί το κοιτάμε ευθεία και είναι τέλεια τοποθετημένο μπροστά μας. Για να δοκιμάσουμε να περιστρέψουμε λίγο την οθόνη πριν τον τοποθετήσουμε με την εντολή rotate. Η εντολή αυτή δέχεται έναν αριθμό που δηλώνει το μέγεθος της περιστροφής σε ακτίνια. Επειδή όμως εγώ (όπως και εσείς φαντάζομαι) είμαι περισσότερο εξοικιωμένος με τις μοίρες, μπορώ να χρησιμοποιήσω τη συνάρτηση radians για να μετατρέψω τις μοίρες που επιθυμώ σε ακτίνια.

size(600,300,P3D);
background(70,0,140);
translate(300,150,0);
rotate(radians(45));
box(100);

Τι έγινε τώρα; Ας τα πάρουμε λίγο με τη σειρά. Η συνάρτηση radians(45) μετατρέπει τις 45 μοίρες σε ακτίνια. Έτσι η rotate(radians(45)) αυτό που κάνει είναι να περιστρέψει τον καμβά 45 μοίρες.

Εγώ όμως δεν ήθελα να περιστρέψω έτσι τον καμβά. Υπάρχουν τρεις άξονες περιστροφής. Ο άξονας Χ (οριζόντιος), ο άξονας Υ (κάθετος) και ο άξονας Ζ ο οποίος χαρακτηρίζει το βάθος του χώρου. Εμείς όταν κοιτάμε μια οθόνη μπορούμε να αντιληφθούμε εύκολα τους άξονας Χ,Υ (πλάτος και ύψος) αλλά δυσκολευόμαστε να κατανοήσουμε τον άξονα Z που είναι το βάθος, γιατί πολύ απλά η εικόνα που βλέπουμε είναι δισδιάστατη.

Ας μείνουμε λίγο στους άξονες Χ και Υ που είναι πιο εύκολοι.

Στην παραπάνω εικόνα φαίνονται οι δυο αυτοί άξονες και τα καμπυλωτά βελάκια δείχνουν πως γίνεται η περιστροφή γύρω από αυτούς. Τώρα αντιλαμβάνομαι και εγώ ότι ήθελα να περιστρέψω τον καμβά ως προς τον άξονα Υ προηγούμενως.

Ο άξονας Ζ δεν φαίνεται στην παραπάνω εικόνα γιατί δείχνει προς το βάθος της οθόνης. Ίσως να μπορέσουμε να το αναπαραστήσουμε στην πιο κάτω εικόνα αν υποθέσουμε ότι βλέπουμε τα πράγματα από μια πιο πλάγια θέση.

Τώρα επίσης αντιλαμβάνομαι ότι η εντολή rotate περιέστρεψε τον καμβά ως προς τον άξονα Ζ τελικά. Ευτυχώς η processing διαθέτει άλλες τρεις εντολές οι οποίες αφορούν ή κάθε μία τον κάθε άξονα.

size(600,300,P3D);
background(70,0,140);
translate(300,150,0);
rotateY(radians(45));
rotateZ(radians(45));
box(100);

Τόση ώρα παρατηρώ ότι ο κύβος μου έχει άσπρο χρώμα με μαύρες ακμές. Φυσικά και εδώ μπορώ να προσθέσω ότι χρώμα θέλω. Οι εντολές fill (χρώμα γέμισης) και stroke (χρώμα ακμής) δουλεύουν όπως ακριβώς και η background.

size(600,300,P3D);
background(70,0,140);
translate(300,150,0);
rotateY(radians(45));
rotateZ(radians(45));
fill(70,150,0);
stroke(35,125,0);
box(100);

Βαρέθηκα με τον κύβο. Μήπως να τον αλλάξουμε σε κάποιο άλλο σχήμα; Π.χ μια σφαίρα; Πολύ απλό, αντί για box ζητάω μια sphere.

size(600,300,P3D);
background(70,0,140);
translate(300,150,0);
rotateY(radians(45));
rotateZ(radians(45));
fill(70,150,0);
stroke(35,125,0);
sphere(100);

Πολύ στατικά δεν είναι όλα; Μήπως να βάλουμε λίγο κίνηση; Πριν όμως προχωρήσουμε στην κίνηση, ας φτιάξουμε την δομή του προγράμματος μας. Μέχρι τώρα βάζαμε τις εντολές μας την μία κάτω από την άλλη χωρίς να τις εντάξουμε σε κάποια ενότητα. Η processing όμως, όπως και το Arduino έχουν 2 ενότητες. Την ενότητα setup() που εκτελείται μια φορά στην αρχή και την ενότητα draw() που εκτελείται συνέχεια. Διορθώνω λοιπόν το μέχρι τώρα πρόγραμμα μας βάζοντας στην setup μόνο την εντολή size και όλες τις υπόλοιπες μέσα στην draw για να εκτελούνται συνέχεια.

void setup() {
  size(600,300,P3D);
}

void draw() {
  background(70,0,140);
  translate(300,150,0);
  rotateY(radians(45));
  rotateZ(radians(45));
  fill(70,150,0);
  stroke(35,125,0);
  sphere(100);
}

Άλλαξε κάτι; Δεν μου φαίνεται. Γιατί όμως; Η αλήθεια είναι ότι τώρα οι εντολές που είναι στην draw εκτελούνται συνέχεια και όχι μόνο μια φορά όπως πριν, αλλά δυστυχώς κάνουν ακριβώς το ίδιο πράγμα κάθε φορά. Τοποθετούν την σφαίρα στο ίδιο σημείο, με την ίδια περιστροφή. Κάθε φορά που η draw ξεκινάει από την αρχή μηδενίζει τις μετακινήσεις και τις περιστροφές και έτσι αυτές δεν λειτουργούν αυξητικά.

Αυτό που μπορώ να κάνω είναι αντί για σταθερούς αριθμούς (πχ 45 μοίρες) να χρησιμοποιήσω μεταβλητές. Μία για τις μοίρες κάθε άξονα περιστροφής. Μπορώ να τις ονομάσω όπως θέλω. Εμένα με βολεύει να τις πω mX, mY και mZ για να τις θυμάμαι (μοίρες Χ,Υ,Ζ) και να τις γράφω εύκολα και γρήγορα.

Αρχικά πρέπει να πω στην processing τι είδους μεταβλητές είναι. Αυτό το κάνω στην αρχή του προγράμματος (πριν από την setup) και επειδή θέλω να είναι ακέραιοι αριθμοί χρησιμοποιώ την λέξη int.

Μετά πρέπει να δώσω μια αρχική τιμή στις μεταβλητές. Θα τις κάνω όλες μηδέν, και αυτό θα γίνει στην setup. Τώρα αυξάνοντας τις τιμές αυτές μέσα στην draw μπορώ να έχω μια διαρκή κίνηση της σφαίρας περιστρέφοντας την σε όποιους άξονες επιθυμώ!

int mX;
int mY;
int mZ;

void setup() {
  size(600,300,P3D);
  mX = 0;
  mY = 0;
  mZ = 0;
}

void draw() {
  background(70,0,140);
  translate(300,150,0);
  rotateX(radians(mX));
  rotateY(radians(mY));
  rotateZ(radians(mZ));
  mX = mX + 1;
  mY = mY + 1;
  mZ = mZ + 1;
  fill(70,150,0);
  stroke(35,125,0);
  sphere(100);
}

1 Σχόλιο

Αφήστε μια απάντηση