-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNotes.tex
1464 lines (1191 loc) · 43.2 KB
/
Notes.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\documentclass[11pt,fleqn]{article}
%% This first part is the document header, which you don't need to edit.
%% Scroll down to \begin{document}
\usepackage[latin1]{inputenc}
\usepackage{enumerate}
\usepackage[hang,flushmargin]{footmisc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{amsthm}
\theoremstyle{definition}
\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}[theorem]{Lemma}
\newtheorem{corollary}[theorem]{Corollary}
\newtheorem{proposition}[theorem]{Proposition}
\newtheorem{definition}[theorem]{Definition}
\newtheorem{example}[theorem]{Example}
\setlength{\oddsidemargin}{0px}
\setlength{\textwidth}{460px}
\setlength{\voffset}{-1.5cm}
\setlength{\textheight}{20cm}
\setlength{\parindent}{0px}
\setlength{\parskip}{10pt}
\begin{document}
\begin{center}
{\Huge
Computer Graphics Notes % e.g. Problem sheet 1
}\\
Ethan Cheng % e.g. Clive Newstead, Saturday 27th June 2015
\end{center}
\begin{abstract} \noindent
Computer Graphics Programming, taught by Jon-Alf Dyrland-Weaver
\end{abstract}
\tableofcontents
\newpage
\section{Feb. 3, 2016 - Image File Formats}
We will be choosing an easy-to-work-with file format for images we're generating...
because this a graphics course. We will be making graphics. That are images. Yes.
\subsection{Compressed vs Uncompressed}
\begin{itemize}
\item Compressed
\begin{itemize}
\item Performs an algorithm on an uncompressed image to reduce file size
\item Smaller
\item Often less information
\end{itemize}
\item Uncompressed
\begin{itemize}
\item Full map of pixel values
\item Raw data
\end{itemize}
\end{itemize}
\subsubsection{Compressed Image Formats}
\begin{itemize}
\item png
\item gif
\item jpeg/jpg
\end{itemize}
\subsubsection{Uncompressed Image Formats}
\begin{itemize}
\item bmp (Bitmap)
\item tiff
\item svg
\item raw
\end{itemize}
\subsection{Lossy vs Lossless}
\begin{itemize}
\item Lossy
\begin{itemize}
\item Compression algorithms lose some of the original information
\end{itemize}
\item Lossless
\begin{itemize}
\item Contains all the original information
\end{itemize}
\end{itemize}
All \textbf{uncompressed} image formats are lossless. Duh. \textbf{JPEG} files are
lossy compressed. However, \textbf{PNG} files are lossless compressed.
\subsection{Run Length Encoding}
We can very easily make a lossless compression algorithm:
\begin{verbatim}
12B: GGGGGYYYRRRR
6B: 5G3Y4R
\end{verbatim}
However, this is a bad compression algorithm for real-life images (i.e. from a
camera), since adjacent pixels will almost NEVER be the same. This is, however, what
the PNG format uses, and is used for flat, ``minimalist'' computer generated images.
\subsection{Raster vs Vector}
\begin{itemize}
\item Raster
\begin{itemize}
\item Image is represented as a grid of pixels
\end{itemize}
\item Vector
\begin{itemize}
\item Image is represented as a list of drawing instructions
\item Scale well
\item SVG stands for ``Scalable Vector Graphics''
\end{itemize}
\end{itemize}
\subsection{So... what are we using? netpbm!}
\texttt{netpbm} is a very simple, raster, lossless, uncompressed format. It is
extremely simple: space separated values of triplet integers from [0,255].
\newpage
\section{Feb. 4, 2016 - Yay! NetPBM!}
\subsection{NetPBM File Format}
NetPBM files are \texttt{.ppm}, plaintext files, interpretted as images.
\subsubsection{File Header}
\begin{itemize}
\item File Header : \texttt{P3}
\item \texttt{XRES} : x-resolution as an integer value of pixels
\item \texttt{YRES} : y-resolution as an integer value of pixels
\item \texttt{MAX\_COLOR\_VALUE} : Maximum color value of a pixel
\end{itemize}
\subsubsection{File Data}
\begin{itemize}
\item $R_n$ : ASCII representation of red value of pixel $n$ (i.e. 255)
\item $G_n$ : ASCII representation of green value of pixel $n$ (i.e. 255)
\item $B_n$ : ASCII representation of blue value of pixel $n$ (i.e. 255)
\end{itemize}
These values can be separated by \textbf{any} type of whitespace:
\begin{itemize}
\item space
\item tab
\item newline
\end{itemize}
Here is a sample file: \texttt{yellow.ppm} (a 5x5 pixel square of yellow):
\begin{verbatim}
P3
5 5
255 255 0 255 255 0 255 255 0 255 255 0 255 255 0
255 255 0 255 255 0 255 255 0 255 255 0 255 255 0
255 255 0 255 255 0 255 255 0 255 255 0 255 255 0
255 255 0 255 255 0 255 255 0 255 255 0 255 255 0
255 255 0 255 255 0 255 255 0 255 255 0 255 255 0
\end{verbatim}
\newpage
\section{Feb. 5 - 10, 2016 - Bresenham's Line Algorithm}
\subsection{Computer Graphics Basics: The Octal Cartesian Plane}
In math, we usually split the Cartesian Plane into \textbf{quadrants}, along
intervals of $90^{\circ}$, going radially.
In computer graphics, it is much easier to subdivide the quadrants into
\textbf{octants}, along intervals of $45^{\circ}$, going radially.
\subsection{Computer Graphics Basics: Lines with Pixels}
In computer graphics, drawing a straight line is a bit strange. Because pixels are
integer values, we don't care about floating point numbers. This is why graphics
cards exist: they are processors that only operate with integers, and are well
optimized and fast.
What about drawing the line? We can come up with a few ideas:
\begin{enumerate}
\item Pick a random point, and those that are on the line, we keep it
\item Calculate the ``delta'' value of $x$ and $y$ based on the slope of the
line, given by the two endpoints
\item Using some forms of the line equations from math
\item Some combination with some clever optimizations of the 3
\end{enumerate}
\newpage
\subsection{Plotting a line without floats}
We have our standard line equation in point--slope form. We can manipulate this to
\textbf{not} use division, which prevents floating point numbers
\begin{align*}
y &= mx + b \\
y &= \frac{\Delta y}{\Delta x} x + b \\
y \Delta x &= x \Delta y + b \Delta x \\
0 &= x \Delta y - y \Delta x + b \Delta x \\
A &= \Delta y \\
B &= -\Delta x \\
C &= b \Delta x \\
0 &= Ax + By + C = f(x, y)
\end{align*}
We end up with our standard line equation from math, which deals strictly with
INTEGER VALUES, since $x$ and $y$ are pixel values, which are integers.
We can simply evaluate $f(x,y)$, and if the result equals $0$, then $(x,y)$ is on the
line.
Let's split up the 8 octants when we consider with pixels when we use our function
$F(x,y)$
Note that we can split this into cases!
\[
f(x,y) = Ax + By + C =
\begin{cases}
= 0 \rightarrow (x,y) \text{ is on the line} \\
< 0 \rightarrow (x,y) \text{ is above the line} \\
> 0 \rightarrow (x,y) \text{ is below the line} \\
\end{cases}
\]
We can get the relations with the line using $B = -\Delta x$.
From this piece-wise evaluation: we only have 2 options when we plot a point from one
endpoint to another:
\begin{enumerate}
\item $(x + 1, y + 1)$
\item $(x + 1, y)$
\end{enumerate}
\newpage
Rather than looking at both of those, we can instead look at the midpoint $(x + 1, y
+ \frac{1}{2})$.
This gives us the following relation:
$
f(x + 1, y + \frac{1}{2}) =
\begin{cases}
< 0 \rightarrow \text{ midpoint is above the line. Draw the lower pixel: } (x + 1, y) \\
0 \rightarrow \text{ midpoint is on the line. Draw either pixel} \\
> 0 \rightarrow \text{ midpoint is below the line. Draw the higher pixel: } (x + 1, y + 1)
\end{cases}
$
\subsection{Algorithm Pseudocode}
We now have our algorithm, so we can write a crude version in pseudocode, drawing a
line from $(x_0, y_0 \rightarrow (x_1, y_1)$.
\begin{verbatim}
1 : // Check if we are in quadrant I
2 : @assert(0 < m and m < 1)
3 : x = x0
4 : y = y0
5 : while (x <= x1)
6 : plot(x, y)
7 : // Calculate the delta using given function f()
8 : d = f(x + 1, y + (1 / 2))
9 : if (d > 0)
10: y = y + 1
11: x = x + 1
\end{verbatim}
However, on line 8, we are recalculating $d$ every single iteration of the loop. We
can bring it out of the loop. We can set the initial value:
\begin{align*}
d &= f(x_0 + 1, y_0 + \frac{1}{2}) \\
&= A(x_0 + 1) + B(y_0 + \frac{1}{2}) + C \\
&= Ax_0 + A + By_0 + \frac{1}{2}B + C \\
&= (Ax_0 + By_0 + C) + A + \frac{1}{2}B \\
&= f(x_0, y_0) + A + \frac{1}{2}B \\
\Delta d &= A + \frac{1}{2}B
\end{align*}
From this, we can improve our pseudocode:
\begin{verbatim}
1 : // Check if we are in quadrant I
2 : @assert(0 < m and m < 1)
3 : x = x0
4 : y = y0
5 : d = A + B / 2
6 : while (x <= x1)
7 : plot(x, y)
8 : if (d > 0)
9 : y = y + 1
10: x = x + 1
11: d = f(x + 1, y + (1 / 2))
\end{verbatim}
This isn't very helpful, since we are still calling \verb|f()| every single
iteration. Let us make a table:
\begin{table}[!htpb]
\centering
\label{bresenham1}
\begin{tabular}{c|c}
$d < 0$ & $d > 0$ \\ \hline \\
$x \rightarrow x + 1$, $y \rightarrow y$ & $x \rightarrow x + 1$, $y
\rightarrow y + 1$ \\
\texttt{f(x+1, y)} & \texttt{f(x+1, y+1)} \\
\texttt{d = d + A} & \texttt{d = d + A + B}
\end{tabular}
\end{table}
This let's us reduce calculating $f()$ to a simple addition.
\begin{verbatim}
1 : // Check if we are in quadrant I
2 : @assert(0 < m and m < 1)
3 : x = x0
4 : y = y0
5 : d = A + B / 2
6 : while (x <= x1)
7 : plot(x, y)
8 : if (d > 0)
9 : y = y + 1
10: d = d + B
10: x = x + 1
11: d = d + A
\end{verbatim}
There is one more flaw: we are dividing by 2 on line 5. We can get rid of this by
doing the following:
\begin{align*}
d &= A + \frac{1}{2}B \\
2d &= 2A + B \\
\end{align*}
This gives us $2d$ instead of $d$. We can change our incrementor statements:
\begin{align*}
d &= d + A &&\rightarrow 2d &&&= 2d + 2A \\
d &= d + A + B &&\rightarrow 2d &&&= 2d + 2A + 2B
\end{align*}
We can patch our implementation:
\begin{verbatim}
1 : // Check if we are in quadrant I
2 : @assert(0 < m and m < 1)
3 : x = x0
4 : y = y0
5: A = y1 - y0
6: B = -(x1 - x0)
7 : d = 2A + B
8 : while (x <= x1)
9 : plot(x, y)
10: if (d > 0)
11: y = y + 1
12: d = d + 2B
13: x = x + 1
14: d = d + 2A
\end{verbatim}
This gives us a valid algorithm for octant 1. Let us extend this to octant 2:
\subsubsection{Extending the algorithm to other quadrants}
We now have a new rule for $m$: $1 < m$. Like in octant 1, where we had:
\begin{enumerate}
\item $(x + 1, y + 1)$
\item $(x + 1, y)$
\end{enumerate}
In octant 2, we have:
\begin{enumerate}
\item $(x, y + 1)$
\item $(x + 1, y + 1)$
\end{enumerate}
This gives us a midpoint of $(x + \frac{1}{2}, y + 1)$, giving us an initial point of
$f(x_0 + \frac{1}{2}, y_0 + 1))$, and $d = \frac{1}{2}A + B$.
Using this, we can adapt our algorithm to octant 2:
\begin{verbatim}
1 : // Check if we are in quadrant I
2 : @assert(0 < m and m < 1)
3 : x = x0
4 : y = y0
5: A = y1 - y0
6: B = -(x1 - x0)
7 : d = A + 2B
8 : while (y <= y1)
9 : plot(x, y)
10: if (d < 0)
11: x = x + 1
12: d = d + 2A
13: y = y + 1
14: d = d + 2B
\end{verbatim}
Octants 5 and 6 are the same as 1 and 2! Likewise, Octants 3 and 4 are the same as 7
and 8, albeit going between the pairs of pairs requires flipping the signs.
In Octant 8, we have
\begin{enumerate}
\item $(x + 1, y - 1)$
\item $(x + 1, y)$
\end{enumerate}
This gives us a midpoint of $(x + 1, y - \frac{1}{2})$, giving us an initial point of
$f(x_0 + 1, y - \frac{1}{2}))$, and $d = \frac{1}{2}A + B$.
\section{Feb. 23 - 24, 2016 - Matrix Math Review}
In order to implement a different method of representing a picture, we have to review
some matrix math:
\subsection{Scalar Multiplcation}
\[
s \cdot
\begin{bmatrix}
a & b \\
c & d
\end{bmatrix}
=
\begin{bmatrix}
sa & sb \\
sc & sd
\end{bmatrix}
\]
Simple!
\subsection{Matrix Multiplication}
Now let's move on to something harder. Matrix Multiplication must satisfy some
requirements:
Given $M_0 M_1$
\begin{itemize}
\item $M_0 M_1 \neq M_1 M_0$
\item The number of columns of $M_0$ must equal the number of rows in $M_1$
\end{itemize}
For instance,
\[
\begin{bmatrix}
a & b & c
\end{bmatrix}
\]
has the shape $1 \times 3$. If this matrix is $M_0$, $M_1$ must have the shape $3
\times n$. For instance:
\[
\begin{bmatrix}
1 \\
2 \\
3
\end{bmatrix}
\]
If we multiply these, we will get:
\[
\begin{bmatrix}
a & b & c
\end{bmatrix} \cdot
\begin{bmatrix}
1 \\
2 \\
3
\end{bmatrix}
=
\begin{bmatrix}
1a + 2b + 3c
\end{bmatrix}
\]
From this we see: if $M_0$ is a matrix of shape $a \times b$ and $M_1$ is a matrix of
shape $b \times c$, $M_0 \cdot M_1$ has the shape $a \times c$.
To find the $(x \times y)$th element is the product of the $x$th row of $M_0$ and the
$y$th row of $M_1$.
For practice:
\[
\begin{bmatrix}
a & b & c \\
d & e & f \\
g & h & i
\end{bmatrix} \cdot
\begin{bmatrix}
1 & 4 \\
2 & 5 \\
3 & 6
\end{bmatrix}
=
\begin{bmatrix}
1a + 2b + 3c & 4a + 5b + 6c \\
1d + 2e + 3f & 4d + 5e + 6f \\
1g + 2h + 3i & 4g + 5h + 6i
\end{bmatrix}
\]
\subsection{Multiplicative Identity Matrix}
There is a Multiplicative Identity Matrix that can have a variable shape, but must
satisfy the following conditions:
\begin{itemize}
\item Square shape (number of rows is equal to number of columns)
\item Diagonal values (items (n,n) for $0 \leq n \leq $Number of rows) are all 1
\item All other values are 0
\end{itemize}
\subsection{Transforming Matrices}
\subsubsection{Scaling}
We can apply this to a simple scaling algorithm:
\[
\begin{bmatrix}
a & 0 & 0 & 0 \\
0 & b & 0 & 0 \\
0 & 0 & c & 0 \\
0 & 0 & 0 & 1
\end{bmatrix} \cdot
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix} =
\begin{bmatrix}
ax \\
by \\
cz \\
1
\end{bmatrix}
\]
This scales the $x$, $y$, and $z$ dimensions by factors of $a$, $b$, and $c$
respectively.
\subsubsection{Translating}
To translate $(x,y,z)$ by $(a,b,c)$ WITHOUT adding the matrices (we want to keep
everything in terms of matrix multiplication.
\[
\begin{bmatrix}
1 & 0 & 0 & a \\
0 & 1 & 0 & b \\
0 & 0 & 1 & c \\
0 & 0 & 0 & 1
\end{bmatrix} \cdot
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix} =
\begin{bmatrix}
x + a \\
y + b \\
z + c \\
1
\end{bmatrix}
\]
\subsubsection{Rotation}
To rotate a point $(x,y,z)$, we must supply a rotation axis and an angle.
Without loss of generality, let's rotate about he $z$ axis:
\begin{center}
$(x,y,z) \rightarrow (?, ?, z)$
\end{center}
To find the two question marks, we must do some trig:
If we convert to polar, we have:
\begin{center}
$x = r\cos(\phi)$ \\
$y = r\sin(\phi)$
\end{center}
If we rotate an angle $\theta$, we rotate to:
\begin{center}
$x_0 = r\cos(\phi + \theta)$ \\
$y_0 = r\sin(\phi + \theta)$
\end{center}
Expanding this out with angle addition formulas, we have:
\begin{align*}
x_0 &= r\cos(\phi + \theta) \\
&= r\cos(\phi)\cos(\theta) - r\sin(\phi)\sin(\theta) \\
&= x\cos(\theta) - y\sin(\theta)
\end{align*}
\begin{align*}
y_0 &= r\sin(\phi + \theta) \\
&= r\sin(\phi)\cos(\theta) + r\cos(\phi)\sin(\theta) \\
&= y\cos(\theta) + x\sin(\theta)
\end{align*}
\section{Feb. 25, 2016 - Rotation Continued}
Now that we have our identities for rotation for the $z$ axis, we can convert it to
rotation about the $x$ and $y$ axis:
\begin{itemize}
\item \textbf{x-axis} \\
\[
\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & \cos\theta & -\sin\theta & 0 \\
0 & \sin\theta & \cos\theta & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
\] \\
$(x,y,z) \rightarrow (x, y\cos\theta - z\sin\theta, y\sin\theta + z\cos\theta)$
\item \textbf{y-axis} \\
\[
\begin{bmatrix}
\cos\theta & 0 & -\sin\theta & 0 \\
0 & 1 & 0 & 0 \\
\sin\theta & 0 & \cos\theta & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
\]\\
$(x,y,z) \rightarrow (x\cos\theta - z\sin\theta, y, x\sin\theta + z\cos\theta)$
\item \textbf{z-axis} \\
\[
\begin{bmatrix}
\cos\theta & -\sin\theta & 0 & 0 \\
\sin\theta & \cos\theta & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
\]\\
$(x,y,z) \rightarrow (x\cos\theta - y\sin\theta, x\sin\theta + y\cos\theta, z)$
\end{itemize}
\subsection{Applying Transformations}
\textit{Note: The transformations we are doing are called} \textbf{affined
transformations}.
Let $E_0$ be our edge matrix, which we have added edges into. Let $T$ be our
translate matrix, $S$ be our scale matrix, and $R$ be our rotate matrix.
$
T \cdot E_0 = E_1 \text{ Translated} \\
S \cdot E_1 = E_2 \text{ Translated, then Scaled} \\
R \cdot E_2 = E_3 \text{ Translated, then Scaled, then Rotated}
$
Note that $E_3 = R \cdot S \cdot T \cdot E_0$. Matrix multiplication is not
commutative, but it \textbf{is} \textit{associative}! We can simply group the
transformations before applying them on $E_0$, which would improve efficiency.
Because our translation matrices are $4 \times 4$, but $E_0$ is $4 \times n$ where
$n$ is an arbitrary number, if $n$ is large, multiplying by a $4 \times n$ 3 times is
quite consuming.
$(R \cdot S \cdot T) \cdot E_0$ will only multiply by a $4 \times n$ once, saving
runtime and resources.
\section{Mar. 7, 2016 - Parametric Equations}
Given $x$ and $y$ equations, we can let $x$ and $y$ be equations of $t$ to create
parametric equations.
Given our line equation that takes $(x_0, y_0)$ to $(x_1, y_1)$, we can create
parametric equations:
\begin{align*}
f(t) &= x_0 + t(\Delta x) \\
g(t) &= y_0 + t(\Delta y)
\end{align*}
We can simply define parametrics for a circle and draw the circle with iterations of
a small amount to iterate $t$:
\begin{verbatim}
double x(double t) {
return 25 * cos(2 * M_PI * t) + XRES / 2;
}
double y(double t) {
return 25 * sin(2 * M_PI * t) + YRES / 2;
}
double step, x0, y0, x, y;
double CEILING = 1.0;
x0 = x(0);
y0 = y(0);
for (double t = step; t < CEILING; t += step) {
x = x(t);
y = y(t);
draw_line(x0, y0, x, y);
x0 = x;
y0 = y;
}
\end{verbatim}
However, due to floating point imprecision, we should make \texttt{CEILING} a bit
higher than 1.0, so a value like $1.0001$.
\section{Mar. 8, 2016 - Splining}
\begin{center}
Hermite Curves
\end{center}
Given $f(t) = at^3 + bt^2 + ct + d$, we can find its derivative $f^{'}(t) = 3at^2 +
2bt + c$. When $t = 0$, $f(t) = d$ and $f^{'}(t) = c$. When $t = 1$, $f(t) = a + b +
c + d$ and $f^{'}(t) = 3a + 2b + c$.
$
\begin{bmatrix}
0 & 0 & 0 & 1 \\
1 & 1 & 1 & 1 \\
0 & 0 & 1 & 0 \\
3 & 2 & 1 & 0
\end{bmatrix}
\times
\begin{bmatrix}
a \\
b \\
c \\
d
\end{bmatrix}
=
\begin{bmatrix}
d \\
a + b + c + d \\
c \\
3a + 2b + c
\end{bmatrix}
=
\begin{bmatrix}
P_0 \\
P_1 \\
R_0 \\
R_1
\end{bmatrix}
$ \\
To obtain
$
\begin{bmatrix}
a \\
b \\
c \\
d
\end{bmatrix}
$, We need the inverse matrix of
$
\begin{bmatrix}
0 & 0 & 0 & 1 \\
1 & 1 & 1 & 1 \\
0 & 0 & 1 & 0 \\
3 & 2 & 1 & 0
\end{bmatrix}
$
which just so happens to be:
$
\begin{bmatrix}
2 & -2 & 1 & 1 \\
-3 & 3 & -2 & -1 \\
0 & 0 & 1 & 0 \\
1 & 0 & 0 & 0
\end{bmatrix}
$
\subsection{Bezier Curves}
We need 4 endpoints! There are some cool animations on wikipedia that can explain: \\
\begin{center}
\texttt{https://en.wikipedia.org/wiki/Bezier\_curve}.
\end{center}
\section{Mar. 10, 2016 - Bezier Curves Continued}
A linear Bezier Curve from $P_0$ to $P_1$ is denoted by the parametric equation
\begin{center}
$P(t) = (1-t)P_0 + tP_1$
\end{center}
A quadratic Bezier Curve with 3 points $P_0$ to $P_2$, with $P_1$ doing the
``tugging'' is denoted by the parametric equation:
\begin{center}
$R(t) = (1 - t)^2 P_0 + 2t(1 - t)P_1 + t^2 P_2$
\end{center}
A cubic Bezier Curve with 4 points $P_0$ to $P_3$, with $P_1$ and $P_2$ tugging, is
denoted by:
\begin{center}
$Q(t) = (1 - t)^3 P_0 + 3t(1 - t)^2 P_1 + 3t^2(1 - t) P_2 + t^3 P_3$
\end{center}
\newpage
\section{Mar. 22, 2016 - 3 Dimensionality}
Now that we have lines, hermite curves, bezier curves, and circles, we want to be
able to generate pseudo-3D images with 2D representations.
\subsection{Spheres}
Let's make a sphere. As we know from Blender, there is the icosphere (formed by
triangles) and the UV sphere (formed by layers of circles).
$
\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & cos\phi & -sin\phi & 0 \\
0 & sin\phi & cos\phi & 0 \\
0 & 0 & 0 & 1
\end{bmatrix} \times
\begin{bmatrix}
r\cos\theta \\
r\sin\theta \\
0 \\
1
\end{bmatrix} =
\begin{cases}
x = r\cos\theta \\
y = r\sin\theta\cos\phi \\
z = r\sin\theta\sin\phi
\end{cases}
$
We have $\theta$ as the circle creation, and $\phi$ as the angle of circle rotation.
We need to check ranges between 0 and $2\pi$ and between 0 and $\pi$ for both
$\theta$ and $\phi$.
Pseudocode for sphere points:
\begin{verbatim}
for p from 0.0 to 1.0:
for t from 0.0 to 1.0:
x = r * cos(pi * t)
z = r * sin(pi * t) cos(2 * pi * p)
z = r * sin(pi * t) sin(2 * pi * p)
\end{verbatim}
Now... onto the tastiest of shapes!
\subsection{The Torus. AKA The Tasty Donut}
If we think about it we can generate a torus by translating about the $y$ axis and
rotating in the $x$ axis. This allows to rotate the circle about an external point,
generating each ``sector'' or ``slice'' of the torus.
We can modify our original matrix operation to translate / rotate our circle to
generate a torus of radius $R$:
$
\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & cos\phi & -sin\phi & 0 \\
0 & sin\phi & cos\phi & 0 \\
0 & 0 & 0 & 1
\end{bmatrix} \times
\begin{bmatrix}
r\cos\theta \\
r\sin\theta + R \\
0 \\
1
\end{bmatrix} =
\begin{cases}
x = r\cos\theta \\
y = \cos\phi(r\sin\theta + R) \\
z = \sin\phi(r\sin\theta + R)
\end{cases}
$
\section{Mar. 29, 2016 - Wireframe and Polygon Meshes}
From our code for adding spheres and tori, here:
\begin{verbatim}
addSphere(Double cx, Double cy, Double cz, Double radius) {
double x, y, z;
for (double p = 0; p < CEILING; p += STEP) {
for (double t = 0; t < CEILING; t += STEP) {
x = radius * cos(t * PI) + cx;
y = radius * sin(t * PI) * cos(p * 2 * PI) + cy;
z = radius * sin(t * PI) * sin(p * 2 * PI) + cz;
addPoint(new Point((int) x, (int) y, (int) z));
}
}
}
addTorus(Double cx, Double cy, Double cz, Double r1, Double r2) {
double x, y, z;
for (float p = 0; p < CEILING; p += STEP) {
for (float t = 0; t < CEILING; t += STEP) {
x = r1 * cos(t * 2 * PI) + cx;
y = cos(p * 2 * PI) * (r1 * sin(t * 2 * PI) + r2) + cy;
z = sin(p * 2 * PI) * (r1 * sin(t * 2 * PI) + r2) + cz;
addPoint(new Point((int) x, (int) y, (int) z));
}
}
}
\end{verbatim}
We see that the points that we insert are always a \textbf{set amount}. This means
for a sphere of radius 5, we may be plotting 4000 points, and eventually, it just
looks like a dot, destroying the 3D aspect.
We move onto wireframe and polygon meshes.
\subsection{Wireframe Meshes}
Wireframe meshes are 3D objects defined by the edges that connect the vertices or
points.
It uses the same edge matrix concepts that we have been dealing with throughout
previous assignments.
\subsection{Polygon Meshes}
Polygon meshes are 3D objects defined by the surfaces (typically triangles or
quadrilaterals, as we've seen in Blender) that cover the object.
However, we need to change our polygon mesh to use \textbf{polygon matrices} rather
than edge matrices.
This allows us to draw faces and surfaces, as well as remove hidden faces and
surfaces, which saves much computation later on down the line.
\subsection{Polygon Matrices}
Like we had with an edge matrix, where we stored 2 points (start and end), in a
polygon matrix of triangles, we store 3 points: the vertices of a triangle. We are
drawing \textbf{3} lines per polygon.
\begin{table}[!htpb]
\centering
\begin{tabular}{|c|c|}
\hline
Edge Matrix & Polygon Matrix \\ \hline
\texttt{plot} & \texttt{plot} \\ \hline
\texttt{drawLine} & \texttt{drawLine} \\ \hline
\texttt{drawLines} & \texttt{drawPolygons} \\ \hline
\texttt{addPoint} & \texttt{addPoint} \\ \hline
\texttt{addEdge} & \texttt{addPolygon} \\ \hline
\end{tabular}
\end{table}
\textbf{NOTE} that in \texttt{addPolygon}, we must add the 3 points in
COUNTERCLOCKWISE fashion.
\section{April 5, 2016: Backface Culling}
Backface culling is a technique to render only forward facing surfaces. The surface
normal, $\vec{N}$, is a vector perpendicular to a plane.
We can compare $\vec{N}$ to the view vector (camera view).
If we look towards an object, then $\vec{N}$ must point towards you. Thus, if the
angle between $\vec{N}$ and the view vector $\vec{V}$ is $\theta$, then $90 \leq
\theta \leq 270$ will create a front facing surface.
Thus, we must use the following algorithm:
\begin{enumerate}
\item Calculate $\vec{N}$ \\
\newline
Cross product of 2 vectors that share endpoint and go in different
directions:
\begin{align*}
\vec{N} &= \vec{A} \times \vec{B} \\
&= <A_yB_z - A_zB_y, A_zB_x - A_xB_z, A_xB_y - A_yB_x>
\end{align*}
\item Find $\theta$ between $\vec{N}$ and $\vec{V}$ \\
\newline
We can just use a default view vector: $\vec{V} = <0, 0, -1>$. We can use the
formula:
\begin{center}
$\cos\theta = \frac{N_xV_x + N_yV_y + N_zV_z}{|\vec{N}||\vec{V}|}$