6 ο Εργαστήριο Σχεδιάζοντας σχήματα από σημεία κορυφών, Θόρυβος-Τυχαίοι Αριθμοί (συνέχεια) Σχεδιάζοντας σχήματα από σημεία κορυφών Με nofill() δηλώνουμε ότι το σχήμα δεν θα έχει γέμισμα με χρώμα Η beginshape() καθορίζει την αρχή δήλωσης των κορυφών του σχήματος Με την vertex() δηλώνονται οι συντεταγμένες κάθε κορυφής Η endshape() καθορίζει τo τέλος δήλωσης των κορυφών του σχήματος Με endshape(close) ορίζουμε ότι θέλουμε να σχεδιαστεί ένα κλειστό σχήμα, δηλ. να σχεδιαστεί γραμμή από το τελευταίο vertex έως το πρώτο vertex. H σειρά με την οποία γράφονται οι κορυφές έχει σημασία. Εδώ η συντεταγμένες όλων των κορυφών είναι ίδιες με το πρώτο παράδειγμα αλλά δεν έχουν την ίδια σειρά. Το σχήμα που προέκυψε είναι διαφορετικό. H συντεταγμένες των κορυφών μπορούν να δωθούν και με χρήση μιας for. 1
Καμπύλες Αν χρησιμοποιήσουμε curvevertex() αντί για vertex() όπως στα προηγούμενα παραδείγματα, τότε θα σχεδιάζονται καμπύλες που από τις κορυφές που ορίζονται. Το πρώτο και τελευταίο σημείο που δηλώνεται για μία καμπύλη αποτελούν τα σημεία ελέγχου (C1, C2) της καμπύλης. Τα σημεία ελέγχου καθορίζουν το σχήμα της καμπύλης στην αρχή και το τέλος της. Καμπύλες Bezier Οι καμπύλες Bezier ορίζονται από σημεία κορυφών και σημεία ελέγχου με την beziervertex(). Τα σημεία ελέγχου καθορίζουν το σχήμα της καμπύλης μεταξύ των σημείων κορυφών. 2
V1 το πρώτο σημείο ορίζεται με vertex C1, C2, V2 Οι πρώτες 4 συντεταγμένες ορίζουν τα δύο σημεία ελέγχου, και οι άλλες 2 του σημείου V2. Για κάθε beziervertex() ορίζονται δύο σημεία ελέγχου Για να εμφανίσουμε μια απότομη στροφή χρησιμοποιούμε τις ίδιες συντεταγμένες το σημείο κορυφής και το επόμενο σημείο ελέγχου. Μπορούμε να βάλουμε σημεία vertex() μεταξύ σημείων beziervertex() αν θέλουμε να σχεδιάσουμε κάποια ευθεία γραμμή. 3
Προσαρμοσμένος Θόρυβος Μπορούμε να γράψουμε μια δική μας συνάρτηση η οποία εφαρμόζει θόρυβο με τον ακριβή τρόπο που επιθυμούμε. Θα χρησιμοποιήσουμε το παράδειγμα του προηγούμενου εργαστηρίου όπου σχεδιάζαμε έναν κύκλο με θόρυβο Perlin και θα το τροποποιήσουμε για να εφαρμόσουμε έναν προσαρμοσμένο θόρυβο. Μέγεθος καμβά Χρώμα φόντου Πάχος γραμμής Εξομάλυνση γραμμών Δεκαδική μεταβλητή radius με αρχική τιμή 100 ακτίνα κύκλου Ακέραια μεταβλητή centx με αρχική τιμή 250 κέντρο κύκλου Χ Ακέραια μεταβλητή centy με αρχική τιμή 150 κέντρο κύκλου Y Χρώμα γραμμής Ορισμός για μη γέμισμα σχημάτων Σχεδίαση κύκλου με κέντρο centx, centy και ακτίνα radius*2 Αλλαγή χρώματος γραμμής Αλλαγή πάχους γραμμής (πιο λεπτή) Ορισμός δεκαδικών μεταβλητών x, y Δεκαδική μεταβλητή noiseval με τυχαία τιμή από 0 έως 10 Ορισμός δεκαδικών μεταβλητών Αρχή σχήματος καμπύλης Ορισμός χρώματος γεμίσματος Επανάληψη από γωνία 0 ο έως 360 ο με βήμα αύξησης 1 ο Σε κάθε επανάληψη αυξάνεται η noiseval κατά 0.1 Η radvariance υπολογίζεται με βάση τη τιμή που επιστρέφει η customnoise με παράμετρο την noiseval Η γωνία μετατρέπεται από μοίρες σε ακτίνια (radians) Υπολογισμός των συντεταγμένων του σημείου στην περίμετρο του κύκλου με ακτίνα thisradius και γωνία rad. Ορισμός σημείου κορυφής καμπύλης Tέλος σχήματος καμπύλης δεκαδικό αριθμό στο σημείο από το οποίο εκλύθηκε. Η συνάρτηση με όνομα customnoise δέχεται μια παράμετρο δεκαδική την οποία ονομάζουμε value. Η παράμετρος θα χρησιμοποιείτε μόνο στη συνάρτηση αυτή με το όνομα value. Η συνάρτηση customnoise έχει τύπο δεδομένων επιστροφής float, συνεπώς όταν ολοκληρωθεί η εκτέλεσή της θα επιστρέψει έναν Με την float retvalue = pow(sin(value), 3) υπολογίζουμε το ημίτονο (συνάρτηση sin) της τιμής value και στη συνέχεια υψώνουμε στη δύναμη 3 (συνάρτηση pow). Δοκιμάστε να τρέξετε το παραπάνω παράδειγμα υψώνοντας σε διαφορετικές δυνάμεις το ημίτονο ξεκινώντας από 1 έως 9 για να διαπιστώσετε πως αλλάζει το σχήμα που προκύπτει. 4
Μελέτη Παραδείγματος Schmoo Eyes float radius = 100; //ορισμός μεταβλητών int centx = 250; int centy = 150; float startnoise, noisestep; //ορισμός μεταβλητών για τη σχεδίαση των ματιών float eyerootx, eyerooty, eyexnoise, eyeynoise; float eyedistrootx, eyedistrooty, eyedistxnoise, eyedistynoise; void setup () { size(500,300); background(255); strokeweight(5); smooth(); framerate(12); //αρχικοποίηση καμβά stroke(0, 30); nofill(); ellipse(centx,centy,radius*2,radius*2); //σχεδίαση αρχικού κύκλου startnoise = random(10); //επιλογή αρχικού θορύβου με τυχαία τιμή από 0 έως 10 noisestep = 0.1; //ορισμός βήματος αύξησης θορύβου eyerootx = (width/2) - 50; //υπολογισμός συντεταγμένων για τη θέση των ματιών eyerooty = height/2; eyexnoise = random(10); //επιλογή αρχικού θορύβου με τυχαία τιμή για τα μάτια eyeynoise = random(10); eyedistrootx = 30; eyedistrooty = 0; eyedistxnoise = random(10); eyedistynoise = random(10); strokeweight(1); float stepstep = 0.01; void draw() { fill(255, random(10)); //ορισμός άσπρου γεμίσματος με τυχαία διαφάνεια nostroke();//σχεδίαση σχημάτων χωρίς περίγραμμα rect(0,0,width,height); //σχεδίαση τετράπλευρου που καλύπτει όλον τον καμβά fill(20, 50, 70, random(50)); //ορισμός χρώματος RGB γεμίσματος με τυχαία διαφάνεια rect(0,0,width,height); //σχεδίαση τετράπλευρου που καλύπτει όλον τον καμβά startnoise += 0.01; noisestep += stepstep; if (noisestep > 5) { //όταν η noisestep γίνει μεγαλύτερη από 5 ή μικρότερη από -5 stepstep *= -1; //τότε η stepstep πολλαπλασιάζεται με -1, δηλ. αλλάζει πρόσημο else if (noisestep < -5) { stepstep *= -1; float x, y; float noiseval = startnoise; fill(255, 150); stroke(20, 50, 70); 5
beginshape(); //αρχή σχήματος vertex((width/2)-20, height); for (float ang = 90; ang <= 430; ang += 15) { //επανάληψη από 90 ο έως 430 ο με βήμα 15 ο noiseval += noisestep; float radvariance = 40 * customnoise(noiseval); //η ακτίνα αλλάζει βάση της τιμής //που επιστρέφει η customnoise float thisradius = radius + radvariance; float rad = radians(ang); x = centx + (thisradius * cos(rad)); //υπολογίζονται οι συντεταγμένες στην περίμετρο y = centy + (thisradius * sin(rad)); //του κύκλου curvevertex(x,y); //ορισμός σημείου καμπύλης curvevertex((width/2)+20, height); curvevertex((width/2)+20, height); vertex((width/2)-20, height); endshape(); //σχεδίαση κάτω μέρους σχήματος (λαιμός) //τέλος σχήματος //σχεδίαση ματιών με θόρυβο στην απόστασή τους eyexnoise += 0.01; eyeynoise += 0.01; float eye1x = eyerootx + (noise(eyexnoise) * 40) - 20; float eye1y = eyerooty + (noise(eyeynoise) * 20) - 10; float eyedistx = eyedistrootx + (noise(eyexnoise) * 20) - 10; float eyedisty = eyedistrooty + (noise(eyeynoise) * 40) - 20; stroke(0); fill(255); ellipse(eye1x, eye1y, 20, 20); ellipse(eye1x+eyedistx, eye1y+eyedisty, 20, 20); fill(0); ellipse(eye1x, eye1y, 5, 5); ellipse(eye1x+eyedistx, eye1y+eyedisty, 5, 5); float customnoise(float value) { //επιστρέφει τιμές από -1 έως +1 float retvalue = sin(value); //υπολογισμός ημιτόνου της παραμέτρου value int count = int((value % 10)); //υπολογισμός πόσες φορές διαιρείται ακριβώς με το 10 //η value και μετατροπή σε ακέραιο αριθμό με int() for (int i = 0; i < count; i++) { //με αυτή τη for υψώνουμε στη δύναμη count το retvalue *= sin(value); //ημίτονο return retvalue; //επιστροφή της τιμής που υπολογίστηκε 6
Μελέτη Παραδείγματος Wave Clock //================================= global vars //Δήλωση μεταβλητών που χρησιμοποιούνται σε όλο το πρόγραμμα //(ονομάζονται καθολικέςglobal). Σε αυτό το πρόγραμμα το όνομα των //καθολικών μεταβλητών ξεκινάει με τον χαρακτήρα _ για βοηθήσουν τον //προγραμματιστή να ξέρει σε οποιοδήποτε σημείο του προγράμματος ότι //αυτή η μεταβλητή είναι καθολική int _num = 10; float _angnoise, _radiusnoise; float _xnoise, _ynoise; float _angle = -PI/2; //η γωνία PI/2 αντιστοιχεί σε -90 ο float _radius = 100; float _strokecol = 254; int _strokechange = -1; //================================= init void setup() { size(500, 300); smooth(); framerate(30); clearbackground(); //αρχικοποίηση μεταβλητών με τυχαίους αριθμούς _angnoise = random(10); _radiusnoise = random(10); _xnoise = random(10); _ynoise = random(10); //συνάρτηση για να «καθαρίζει» τον καμβά. Εφαρμογή άσπρου χρώματος //φόντου void clearbackground() { background(255); //================================= frame loop void draw() { //αλλαγή ακτίνας με θόρυβο Perlin (συνάρτηση noise) ώστε οι γραμμές που //θα σχεδιαστούν στη συνέχεια να έχουν διαφορετικό μήκος σε κάθε frame _radiusnoise += 0.005; _radius = (noise(_radiusnoise) * 550) +1; //Χρήση της _angnoise για να εφαρμοστεί θόρυβος Perlin στη γωνία την //οποία θα σχεδιαστούν στη συνέχεια οι γραμμές. Έτσι η απόσταση μεταξύ //των γραμμών θα είναι μεταβλητή _angnoise += 0.005; _angle += (noise(_angnoise) * 6) - 3; if (_angle > 360) { _angle -= 360; //πράξεις ώστε η γωνία να είναι if (_angle < 0) { _angle += 360; //πάντα από 0 ο έως 360 ο // μετακίνηση του κέντρου του κύκλου -10 έως +10 pixels πάλι με χρήση //θορύβου Perlin _xnoise += 0.01; _ynoise += 0.01; float centrex = width/2 + (noise(_xnoise) * 100) - 50; float centrey = height/2 + (noise(_ynoise) * 100) - 50; 7
//Υπολογισμός συντεταγμένων σημείου στην περίμετρο του κύκλου με //ακτίνα _radius και γωνία _angle. float rad = radians(_angle); float x1 = centrex + (_radius * cos(rad)); float y1 = centrey + (_radius * sin(rad)); //Υπολογισμός συντεταγμένων του αντίθετου σημείου από αυτό που //υπολογίστηκε παραπάνω, προσθέτοντας το PI στη γωνία, δηλ. 180 ο float opprad = rad + PI; float x2 = centrex + (_radius * cos(opprad)); float y2 = centrey + (_radius * sin(opprad)); //Το χρώμα της γραμμής (_strokecol) ξεκινάει από 254 (σχεδόν άσπρο) //και μειώνεται κάθε φορά κατά 1 (_strokechange) μέχρι να γίνει 0 //(μαύρο). Με τις δύο if εξασφαλίζεται ότι πάντα το χρώμα θα αλλάζει //από 254 έως 0 και το αντίστροφο. nofill(); _strokecol += _strokechange; if (_strokecol > 254) { _strokechange *= -1; if (_strokecol < 0) { _strokechange *= -1; stroke(_strokecol, 60); strokeweight(1); //σχεδίαση γραμμής μεταξύ των δύο αντίθετων σημείων line(x1, y1, x2, y2); //================================= //Με τη συνάρτηση keypressed ελέγχουμε αν πατήθηκε το πλήκτρο Enter. Σε //αυτή τη περίπτωση αποθηκεύουμε σε εικόνα το τρέχων frame. void keypressed() { if (keycode == ENTER) { saveframe("waveclock-####.tif"); //Με τη συνάρτηση mousepressed ελέγχουμε αν πατήθηκε το πλήκτρο του //ποντικιού. Σε αυτή τη περίπτωση καλείτε η clearbackground που //«καθαρίζει» τον καμβά. void mousepressed() { clearbackground(); 8