This topic is covered in: - Lecture 1, Lecture 2 (start) - TA 1, TA 2
$$ u \cdot v = ||u|| \cdot ||v|| \cdot \text{cos}(\angle uv) $$
מחזירה ווקטור ניצב למישור שנוצר בין שני הווקטורים עם אורך $$ ||u|| \cdot ||v|| \cdot \text{sin}(\angle uv) $$
מוסיף את הרעיון של נקודות למרחב ווקטורי. אסור לחבר/להחסיר נקודות. מותר להוסיף ווקטור לנקודה. מותר לקחת קומבינציה אפינית של שתי נקודות. (סט כל הקומבינציות האפיניות בין שתי נקודות זה הישר שהן יוצרות).
משוואה שכל הפתרונות שלה מייצגים את הצורה. לדוגמא קו ישר בדו מימד: $f(x,y) = ax + by + c =0$ לדוגמא עיגול: $x^2 + y^2 - r^2 = 0$
פונקציה שממפה ממרחב פרמטרי לצורה. לדוגמא קו ישר בדו מימד: $L(t) = O + tD$ לדוגמא עיגול: $(r \cos \theta, r \sin \theta)$
$$ (x,y) \to (x + a, y + b) $$
$$ (x,y) \to (ax, y + b) $$
$$ (x,y) \to (x \cos \theta - y \sin \theta, x \sin \theta + y \cos \theta) $$
אפשר לייצג כל פעולה כזאת כמטריצה, חוץ מטרנסלציה. עבור טרנסלציה מוסיפים למטריצה ולווקטור קואורדינטה הומוגנית כך שהנקודות במרחב "projective". כל הנקודות (hx, hy, h) מתשתייכות לנקודה (x,y,1) במרחב הפרויקטיבי
Translate: $$ \begin{bmatrix} 1 & 0 & a \ 0 & 1 & b \ 0 & 0 & 1 \ \end{bmatrix} \begin{bmatrix} x \ y \ 1 \ \end{bmatrix} = \begin{bmatrix} x + a \ y + b \ 1 \ \end{bmatrix} $$ Scale: $$ \begin{bmatrix} a & 0 & 0 \ 0 & b & 0 \ 0 & 0 & 1 \ \end{bmatrix} \begin{bmatrix} x \ y \ 1 \ \end{bmatrix} = \begin{bmatrix} ax \ by \ 1 \ \end{bmatrix} $$ Rotate: $$ \begin{bmatrix} \cos \theta & - \sin \theta & 0 \ \sin \theta & \cos \theta & 0 \ 0 & 0 & 1 \ \end{bmatrix} \begin{bmatrix} x \ y \ 1 \ \end{bmatrix} = \begin{bmatrix} x \cos \theta - y \sin \theta \ x \sin \theta + y \cos \theta \ 1 \ \end{bmatrix} $$
Around the 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} \begin{bmatrix} x \ y \ z \ 1 \ \end{bmatrix} = \begin{bmatrix} x \ y \cos \theta - z \sin \theta \ y \sin \theta + z \cos \theta \ 1 \ \end{bmatrix} $$
מה אם נרצה לסובב סביב ציר כללי? (זה נקרא axis angle)
הרעיון: לגרום לציר הכללי להיות ציר ה-Y, ואז לסובב סביב ציר ה-Y ואז להחזיר. 1. לסובב סביב ציר ה-x כך שהציר הכללי יהיה במישור ה-xy. 2. לסובב סביב ציר ה-z כך שהציר הכללי יהיה במישור ב-yz. 3. לסובב סביב ציר ה-y בזווית הרצויה. 4. להפעיל את הסיבוב ההפוך ב-z. 5. להפעיל את הסיבוב ההפוך ב-x.
הזוויות הללו נקראות זוויות אוילר. איך מוצאים אותן? מטילים את ווקטור הציר הכללי ומחשבים זווית בעזרת atan2, מסובבים ומחשבים עוד זווית עם atan2, וזהו. (אם אראה שאלה במבחן כלשהו ארחיב).
זה מתאפשר בזכות המשפט הבא:
לכל סיבוב סביב ציר כללי, קיים סיבוב אחד סביב צירי x,y,z (בסדר הזה) בעזרת זוויות אוילר שייתן את אותה תוצאה. (גם בכל סדר אחר יהיה פתרון אבל לא זהה)
אבל... יש בזה בעיה אם מעניינת אותנו האינטרפולציה בין הזוויות ולא רק התוצאה הסופית. אם עושים את האינטרפולציה בזווית בכל אחד מהצירים בנפרד המעבר יראה מוזר בגלל GImbal lock. הפתרון? שימוש ב-Quaternions. בנוסף צריך 16 משתנים אבל עם quartenions צריך רק 4.
דרך אלטרנטיבית לייצג סיבובים. תזכורת מרוכבים: $$ z \cdot w = r_1 \cdot r_2 \cdot (\cos (\theta + \phi) + i \sin (\theta + \phi)) $$ אז לכפול במספר מרוכב עם נורמה 0 זה כמו סיבוב! (בדו מימד) אנו רוצים להרחיב את זה לתלת מימד. $$ q = a + bi + cj + dk $$ ויש צמוד ונורמה $$ \bar{q} = a - bi - cj - dk $$ $$ ||q|| = \sqrt{a^2 + b^2 +c^2 + d^2} $$ ויש סט חוקים של הכפלה ש״לא צריך לשנן״ (ותלויות בסדר). (בריבוע הכול מינוס 1). מדמיינים כדור יחידה במרחב ה-4 מימדי, שניתן למפות למרחב תלת מימדי שלם בצירי ה-i,j,k. מסקנה סופית: בהינתן ציר סיבוב (x,y,z) וזווית תטא, עושים: $$ q = \cos (\theta / 2) + \sin (\theta / 2) (xi, yj, zk) $$ $$ q \cdot v \cdot \bar{q} $$ אם רוצים לשלב כמה סיבוב אפשר להכפיל קודם את הקוורטרניונים ואז לכפול בווקטור. כשעושים אינטרפולציה עושים לזווית ולא לווקטור עצמו.
נניח שיש לנו ייצוג של מישור, בצורה הסתומה (כלומר Ax + By + Cz +D =0) אז יש דרך יעילה להפעיל את הטרנספורמציה, והיא: $$ (T^{-1})^{T} \cdot \begin{bmatrix} A \ B \ C \ D \end{bmatrix} $$
This topic is covered in: - Lecture 2 (end), Lecture 3, Lecture 4 - TA 3 (start)
- קואורדינטות אובייקט - קואורדינטות עולם - קואורדינטות עין (אחרי סיבוב של כל העולם כדי שהעין תסתכל לכיוון -z) - קואורדינטות clipping (אחרי הטלה אורתוגרפית / פרספקטיבה, עדיין תלת מימדי כדי לשמור מידע עומק (לפני חלוקה בקואורדינטה ההומוגנית)) - קואורדינטות מכשיר (אחרי חלוקה בקואורדינטה ההומוגנית, עדיין תלת מימדי) - קואורדינטות חלון (מנורמלות לפי גודל החלון) ה-rasterizer עובד על קואורדינטות החלון ומייצר פיקסלים.
הטלה לאורך קווים ישרים למישור. אם מרכז ההטלה (איפה שהקויים נפגשים) הוא באינסוף, זה נקרא הטלה מקבילה. אם מרכז ההטלה סופי זו הטלת פרספקטיבה.
- הטלה מקבילה שבה המישור ניצב לקרניים (לרוב ניצב לאחד הצירים, כמו שרטוטים בתוכנות קאד). - מוגדר ה-DOP - direction of projection הטלה איזומטרית - סוג של אורתוגרפית שהמישור ניצב לווקטור 1,1,1. נקרא כך כי כשמסתכלים על ראשית הצירים מקבלים 3 זוויות שוות של 120. - מטריצה שעושה הטלה אורתורגרפית על מישור z=0: $$ \begin{bmatrix} 1 & 0 & 0 & 0 \ 0 & 1 & 0 & 0 \ 0 & 0 & 0 & 0 \ 0 & 0 & 0 & 1 \ \end{bmatrix} \begin{bmatrix} x \ y \ z \ 1 \ \end{bmatrix} = \begin{bmatrix} x \ y \ 0 \ 1 \ \end{bmatrix} $$ - אבל אי אפשר להשתמש בה בפייפליין הגרפיקה כי היא מאבדת מידע עומק, וצריך לזכור מה מסתיר את מה! - אז בונים מטריצת ״הטלה״ שלא באמת עושה הורדת מימד, אלא מעבירה הכול לתיבה ב-$[-1,1]^3$. $$ \begin{bmatrix} \frac{2}{r-l} & 0 & 0 & -\frac{r+l}{r-l} \ 0 & \frac{2}{t-b} & 0 & -\frac{t+b}{t-b} \ 0 & 0 & \frac{-2}{f-n} & -\frac{f+n}{f-n} \ 0 & 0 & 0 & 1 \ \end{bmatrix} $$
- מוגדר ה-לCOP - Center of projection - יש נקודות מגוז (vanishing point), והן לא חייבת להיות בתוך התמונה. יכולה להיות נקודה אחת, שתיים או שלוש (שנוצרות מהצירים הראשיים). - מטריצה שעושה הטלת פרספקטיבה על מישור z=d כאשר מסתכלים עליו מראשית הצירים: $$ \begin{bmatrix} 1 & 0 & 0 & 0 \ 0 & 1 & 0 & 0 \ 0 & 0 & 1 & 0 \ 0 & 0 & 1/d & 0 \ \end{bmatrix} \begin{bmatrix} x \ y \ z \ 1 \ \end{bmatrix} = \begin{bmatrix} x \ y \ z \ z/d \ \end{bmatrix} \to \begin{bmatrix} xd/z \ yd/z \ zd/z \ 1 \ \end{bmatrix} $$ נשים לב שעושים את הנרמול של חלוקה של כל הכניסות בכניסה האחרונה כך שתהיה 1. שוב יש את הבעיה שזה מוריד מימד ולא משמר עומק. - אז נגדיר מטריצה חדשה. שוב מניחים שהמצלמה ב-0,0 ומסתכלת לכיוון ה-z השלילי. שוב מעבירה הכול לתיבה ב-$[-1,1]^3$. $$ \begin{bmatrix} \frac{2n}{r-l} & 0 & \frac{r+l}{r-l} & 0 \ 0 & \frac{2n}{t-b} & \frac{t+b}{t-b} & 0 \ 0 & 0 & -\frac{f+n}{f-n} & \frac{-2fn}{f-n} \ 0 & 0 & -1 & 0 \ \end{bmatrix} $$ לא פיתחנו אותה ממש לעומק. רק אינטואיציה. לוקחים פירמידה, עושים shearing כדי שהמרכז שלה יהיה בציר ה-z, מרחיבים את הזווית שלה ל-45, ועושים פרספקטיבה.
אלו אלגוריתמים שמקבלים קואורדינטות חלון כבר אחרי כל העיבודים. ומבינים מה מסתיר את מה.
האלגוריתמים מתחלקים לשתי קבוצות: 1. דיוק-תמונה Image precision. אכפת לנו מה רואים בכל פיקסל (יותר מעניין אותנו ומה שנפוץ היום כי עובד בחומרה) 2. דיוק אוביקט objct precision. אכפת לנו אילו חלקים של אוביקט ניתן לראות בייצוג רציף (אלגוריתמים יותר אנליטים שנותנים דיוק שלא תלוי ברזולוציה)
- טריק שנותן לנו להיפטר מאובייקטים בהתחלה. - מסירים את כל הפוליגונים שהנורמל שלהם פונה הרחק מהמצלמה (ציר ה-z השלישי). - בפועל מסתכלים על המכפלה הסקלארית בין זווית הצפייה לנורמל. אם היא חיובית זורקים את הפוליגון.
- מסוג image precision - עבור כל פיקסל, יש מיקום על מישור התמונה, אז מוציאים משם קרן ובודקים את החיתוך שלה עם כל האובייקטים בתמונה, ובוחרים את האובייקט שהכי קרוב. - זמן ריצה נאיבי אם יש p פיקסלים ו-N פרימיטיבים: $O(pN)$
- מסוג image precision - לאורך הריסטור שומרים z-buffer שהוא מערך בגודל של התמונה שאומר לנו כמה כל אובייקט קרוב. ו-frame buffer שהוא התמונה עצמה. - ה-z buffer מאותחל להיות העומק המקסימלי בכל מקום וה-frame buffer מאותחל להיות צבע הרקע. - עוברים על כל הפוליגונים בסצנה, עבור כל הפיקסלים שהפוליגון מכסה מחשבים עומק. - אם העומק קרוב יותר, מחשבים גם צבע ומעדכנים את העומק והצבע. - אפשר לחשב את העומק incrementally.
- הרעיון הוא למיין קודם את הפוליגונים ואז פשוט לצייר אותם מהרחוק לקרוב. - האם תמיד ניתן למצוא סדר? לא אם יש הסתרות ציקליות. אבל יש דרך להתמודד עם זה בעזרת מישורים מפרידים. - עקרון ההפרדה המישורי: אם יש מישור שמפריד בין שתי קבוצות של אוביקטים, ונקודת המבט היא בצד אחד של המישור, ניתן להניח שכל מה שבצד של נקודת המבט לא מוסתר על ידי משהו בצד השני.
- מבנה נתונים שימושי - בכל קודקוד יש מישור חוצה - העלים הם לא האובייקטים בסצנה, האובייקטים שמורים בצמתים - ואז אם נגיד רוצים לבדוק חיתוך בין אובייקטים אפשר לבדוק אם הם באותם צדדים של המישורים או לא. - המבנה מניח שהסצנה סטטית אבל אפשר להזיז את נקודת המבט.
- סוג של אלגוריתם list priority - שלבים: - מסוג object precision - לבנות עץ BSP. דרך נפוצה לעשות את זה היא שהפוליגונים עצמם יהיה המישורים המפרידים. ייתכן שאם עושים כך נחתוך פוליגונים, אבל זה בסדר פשוט נפצל אותם. בנוסף אם לא עושים בחירות מוצלחות העץ לא יהיה מאוזן. מצד שני לבנות עץ אופטימלי זו בעיה NP קשה ולכן לרוב עושים את זה בצורה רנדומית. - נעבור על האובייקטים בעץ מהרחוק לקרוב על פי מיקום המצלמה - ״נוח לשאול על זה שאלות בבחינה״.
שיטה לייצוג אובייקטים לא בעזרת פוליגונים, אלא בעזרת פעולות בוליאניות על אובייקטים יותר פשוטים. זה טוב כי זה לא מייצג רק את הקליפות של אובייקטים אלא גם את הנפח שלהם. אז מה יש בפריימוורק: 1. פרימיטבים 2. טנרספורמציות אפיניות 3. פעולות בוליאניות
ניתן לייצג כל אובייקט שבונים כגרף עץ. יש אלגוריתם point membership classification,
- לבדיקה אם נקודה מוכלת באובייקט csg. - אלגוריתם רקורסיבי - מתחילים בשורש של העץ. - אם מגיעים לעלה (שמייצג פרימיטיב), פשוט בודקים אם הנקודה בפרימטיב. - אם מגיעים לצומת שמייצג טרנפורמציה, מפעילים את הטרנספורמציה ההפוכה על הנקודה. - אם מגיעים לצומה שמייצג פעולה בוליאנית פועלים לפי הפעולה. יש לשים לב שיש לוגיקה של שלושה ערכים: in, out, on - נשים לב שיש מקרה קצה בחיתוך של on on, כי אם מקבלים משהו בלי נפח (נקודה, קו, מישור) התוצאה אמורה להיות ריקה
This topic is covered in: - Lecture 5, Lecture 6 (start)
מודלים מתמטיים שמייצגים את מרחב הצבעים
- מתבסס על ניסוי שעשו: על ידי קומבינציה של שלושה ספקטרומים / פונקציות בסיס ספציפים RGB ייצרו צבעים שונים עד שבני אדם לא יכלו להבחין בין הקומבינציה לבין צבע כלשהו אחר. - מסקנה - את רוב הצבעים ניתן ליצור בעזרת קומבינציה של אדום, כחול וירוק (לא כולם). - מסקנה 2 - כן ניתן לאפיין כל צבע בעזרת שלושה פנסים כלשהם.
- המטרה - להגדיר שלושה ספקטרומים שבעזרת שילוב שלהם אפשר להגדיר כל אחד מהצבעים בתחום הנראה, תחת המגבלות: - המקדמים XYZ יהיו חיוביים - הקואורדינטה Y תגיד כמה האור בהיר לעין - כאשר X=Y=Z=1/3 נקבל אור לבן כלומר ספקטרום אחיד
- מפריד בין הכרומטיות של הצבע לבהירות. - ניתן לעבור בקלות בין המרחב הזה ל-XYZ - קואורדינטות xy זה ה-chromaticity ומגדירים: $$ x = \frac{X}{X + Y + Z}, y = \frac{Y}{X + Y + Z}, z = \frac{Z}{X + Y + Z} $$ אם מורידים מימד ל-xy וממפים מקבלים דיאגרמת כרומטיסיטי
- הנקודה x=1/3, y=1/3 זה לבן - הצבעים שמתאימים לספקטרום באורך גל בודד זו השפה של הפרסה (בלי הקו למטה). נקראים צבעים רווים - Saturated. (לבן זה הצבע הכי פחות רווי). - הקו למטה שמחבר את הקו לאדום זה ציר הסגולים - הלוקוס הפלנקיאני זה העקום שפולט גוף שחור בטמפרטורות שונות - הכול מתנהג ליניארי, אם משלבים צבעים מקבלים קו ביניהם - גאמוט
- הקבוצה של כל הצבעים הנראים שאמצעי פלט יכול להציג - תלוי בפינות שלו ב-chromaticity diagram. הצבעים שהוא יציג יהיו המשולש שהפינות האלה יוצרות. - למסכים שונים / מצלמות שונות /מדפסות שונות יש גאמוטים שונים. - המרה בין גאמוטים: - דרך אחת לא כזאת טובה היא פשוט לעשות scaling לגאמוט המקורי כך שיכנסו בגאמוט היעד - דרך אחרת היא להזיז רק את הצבעים שנמצאים בגאמוט הישן ומחוץ לגאמוט היעד על ידי קירוב לנקודה הלבנה
מערכת הראייה האנושית לא רגישה אותו דבר להבדלים בין צבעים במקומות שונים ב-XYZ. בכחול רגישים יותר להבדלים קטנים, באדום קצת פחות ובירוק ממש פחות. זה לא תמיד רצוי.
- מרחב שהוא טרנספורמציה לא ליניארית ל-XYZ - מתבסס על מדידות כך שההבדלים התפיסתיים של בני אדם בצעדים שווים לאורך המרחב יהיו שווים - רכיבים: בהירות L, רכיב ירוק אדום a, רכיב צהוב כחול b.
- תלוי מכשיר - יש טרנספורמציה ליניארית מ-XYZ ל-RGB (אבל ייתכן שנקבל מספרים מחוץ לתחום (0,1))
- תלוי מכשיר - דקות - לעומת מסך כשמשלבים הכול מקבלים שחור. - אז הוסיפו דיו רביעי שחור K והאלגוריתם הוא כזה, בהנחה שמקבלים שלשה CMY: - K := min(C,M,Y) - C := C-K - M := M - K - Y := Y - K
- עבור נוחות של בחירת צבעים - hue, saturation, (brightness) value
This topic is covered in: - Basic: TA 3 (end), TA 4 - Ray tracing: TA 7, TA 8 - Photon mapping: Lecture 9 - Path tracing: TA 9 - Environment / spherical harmonics: TA 11
$$ L_o(x, \omega_o)=L_e(x,\omega_0) + \intop_{\omega_i \in \Omega} f_r(x,\omega_i,\omega_o) (\omega_i \cdot n) L_i (x,\omega_i) d \omega_i $$ - כל שיטות התאורה מנסות לשערך את המשוואה הזאת - מתאר את סך האור שיוצא מהנקודה $x$ בכיוון $\omega_o$ - $\Omega$ הוא המיספרה - $f_r$ הוא ה-BRDF - bidirectional reflectance distribution function. זה מתאר את המידע על רמת המבריקות של האובייקט, הצבע שלו וכו
1. אור כיווני (directional light) 2. אור נקודתי (point light)
עוצמה של אור נחלשת פרופורציונלית בריבוע המרחק. אפשר לעשות אופטימיזציה ולהניח שמעבר לטווח מסוים זה 0 (זה נקרא attenuation).
לסיכום עבור point lights: $$ L_i(x,\omega_i) = c \cdot \frac{1}{1+d^2} $$ וגם כיוון האור משתנה פר נקודה בסצנה. אבל עבור directional light האינטנסיטי קבוע, וגם כיוון האור קבוע.
- מכיל 3 רכיבים: - תאורה אמביאנטית - הקירוב ל-Global illumination כלומר האור שלא מגיע ישירות ממקור תאורה - תאורה דיפיוזיבית - אור מט - תאורה ספקולרית - אור משתקף - נגדיר צריך לכל רכיבים להגדיר צבע תאורה וצבע של חומר והם נפרדים. (שזה לא נכון פיזיקלית). $l_a, l_d, l_s, c_a, c_d, c_s$
- כמו phong, אבל קצת משנה את הרכיב הספקולרי. - נסמן את h להיות הווקטור הממוצע של l ו-v. - אז בלין שם לב שהזווית בין h ל-n מתנהגת דומה לזווית בין v ל-r. - אז הצבע הספקולרי הוא: $max(n \cdot h, 0)^\sigma \cdot c_s \cdot l_s$ - וזה טיפה פחות טוב אבל יותר יעיל :). - ספציפית כאשר משתמשים במצלמה אורתוגרפית, ובאור כיווני, אז v ו-l הם קבועים, אז h הוא קבוע.
עכשיו בהינתן המודל הזה יש כמה דרכים לעשות הצללה, כתלות בנורמל שאנו מייחסים.
שומרים נורמל אחד עבור כל פוליגון
שומרים נורמל עבור כל קודקוד, מחשבים צבע לכל קודקוד ועושים אינטרפולציה לצבע. - לא נראה טוב בספקולריות
שומרים נורמל עבור כל קודקוד, ועושים אינטרפולציה לנורמל. ואז מחשבים את הצבע לכל פיקסל.
הרעיון הוא להוציא קרניים מכל פיקסל במצלמה ולעקוב אחריהן.
- מכל פיקסל יורים קרן. - בכל פגיעה הקרן מתפצלת ל-3: - קרן Reflection - קרן Refraction - קרן Shadow - מסכמים את התרומות של כל הקרניים כדי לחשב את צבע הפיקסל הסופי. - חישוב כיוון הקרן הראשונית: בהנחה שמשתמשים במצלמה פסרפקטיבית לוקחים ווקטור ממיקום המצלמה למיקום המתאים במישור התמונה. - חיתוך עם הסצנה: בעזרת נוסחאות אנליטיות של חיתוך עם כל אחד מהפרימטיבים בסצנה. - חישוב תאורה: נגדיר $$ \text{trace}(o,d,e) = {{ \begin{matrix} e c_{\text{hit}} \ e c_{\text{miss}} \end{matrix} } $$ בנוסף נגדיר את ערך ה-visibilty $v(p)$ להיות 0 אם ה-Shadow ray נתקל במשהו בדרך למקור האור מנקודת הפגיעה, ו-1 אם לא.
חוק Snell אומר שהיחס בין סינוס הזוויות שווה ליחס בין ה-refractive indices. נסמן ב-t אז כיוון הווקטור לאחר refraction. יש חישוב מורכב כדי להשיג אותו. משוואות פרסנל עוזרות להבין מה היחס בין reflection ל-refraction של חומר מסוים.
אז לסיכום נגדיר: $$ c_{hit} = v(p + \varepsilon n) \text{BlinnPhong}(p,d) + trace(p + \varepsilon n,r, k_s e) + trace(p + \varepsilon n,t, f_t e) $$ $$ c_{miss} = \text{skybox}(d) $$ - סיבוכיות: כאשר P מספר הפרימיטיבים, M מספר הפיקסלים, R עומק הרקורסיה, S כמות מוקדי התאורה. $$ O(M\cdot(2^R-1)(P + PS)) $$
במקום לירות קרן אחת לכל פיקסל יורים כמה
אפשר לשלוח כמה קרניים באופן אקראי לפי ה-BRDF כדי לקבל soft shadows.
בניגוד ל-ray tracing שבו יורים קרניים מהמצלמה, ב-photon mapping מתחילים
זה בא לפתור כמה דברים שאין ב-ray tracing - דליפת צבע (Color Bleeding). למשל אם יש בננה ליד קיר יהיה צהוב על הקיר (למרות שהקיר דיפיוסיבי לחלוטין). / Global illumination - תופעת ה-Caustics. תבניות אור מוזרות שנוצרות מתחת למים. כמו עדשות שמרכזות אור. LS+DS*E
- קלאסי: L(D|S)E - ריי טרייסינג קלאסי: L(D|S)S*E - פאת׳ טרייסינג: L(S|D)*E - פוטון מאפינג: L(S|D)*E
- איך עושים את התרומה הדיפיוסיבית? דגימה של חצי ההמיספירה ומשקול לפי ה-BRDF (מניחים שאנחנו בדיוק במרכז ה-cube map, ומסתכלים ממש על כל פיקסל ופיקסל בחצי ההמיספרה). נשים לב שצריך לעשות נרמול כלשהו באינטגרל על הקואורדינטות הספריות. - בגלל שזה יקר נעשה את החישוב הזה מבעוד מועד. כלומר ניצור cube map חדש ואז נשתמש בו. - אפשר לעשות את זה באופן טוב יותר עם spherical harmonics - למה זה עדיף? - לא דורש זיכרון (רק 9-16 מקדמים) - מהיר. לא דורש דגימה מטקסטורה
This topic is covered in: - TA5, TA6
מיפוי ידני של הטקסטורה לאובייקט
הטלה של הטקסטורה על צורה פרימיטיבית: 1. מיפוי מישורי: ממפים על מישור ספציפי $(u,v)=(x/w,z/h)$ 2. מיפוי קופסא / triplanar: כמו מישורי, אבל מטילים על מישור מכל כיוון בהתאם לנורמל של המשטח. 3. מיפוי ספירי: עוברים מקואורדינטות קרטזיות לקואורדינטות ספריות, ואז ממפים לטקסטורה .$r=\sqrt(x^2 +y^2 +z ^2)$, $\theta = \text{atan2}(z,x)$, $\phi = \text{acos}(y/r)$. ואז: $u=0.5 + \theta/2\pi$, $v=1-\phi / \pi$ 4. מיפוי גלילי: דומה לספירי
לרוב הטקסטורה לא בדיוק בגודל המסך. אז יש כמה דרכים לדגום טקסלים. 1. שיטת nearest neighbor - ממש גרוע 2. אינטרפולציה ביליניארית - אינטרפולציה בציר ה-u ו-ה-v כתלות במיקום המדויק של הנקודה
הקטנה של טקסטורות. 1. אינטרפולציה ביליניארית רגילה עם 4 שכנים זה לא טוב, רוצים יותר שכנים אבל זה איטי! 2. אז עושים משהו שנקרא mipmap - מחשבים פעם אחת בכל מיני גדלים שונים ועושים caching. 3. שיטת anisotropic filtering - כמו mipmapping אבל עושים גם לכל ציר בנפרד, נראה יותר טוב
1. מפת אלבדו - הצבע ה״טהור״ של האובייקט. 2. מפת ספקולריות - אומרת איפה האובייקט ספקולרי. 3. מפת גובה (height map) - אומרת מה יותר גבוה.
יש שתי שיטות להשתמש בטקסטורת הגובה:
- משתמשים במפת הגובה כדי אשכרה להזיז את הגיאומטריה ב-vertex shader. - זה נראה טוב אבל זה הרבה יותר יקר ודורש שתהיה בגיאומטריה שלנו יהיו המון קודקודים. - איך? מזיזים כל קודקוד בכיוון הנורמל לפי הגובה במפת הגובה.
- כאן במקום לשנות את הגיאומטריה, משנים פשוט את הכיוון של הנורמל, כאילו הגיאומטריה הייתה שם. - ואז ההבדל מתבטא כאשר עושים את חישובי התאורה (למשל בלין פונג) עם הנורמלים החדשים. - איך? - מחשבים, על פי מפת הגובה, משהו שנקרא - Normal map. - עושים זאת על ידי תנועה בדלטא קטן בשני הצירים, בכך חישוב הווקטורים שיוצרים מישור ואז כפל ווקטורי שלהם כדי לקבל את הנורמל. - אבל יש פה דקות של איך קובעים את הנורמל האובייקט בעולם לפי הנורמל ממפת הנורמלים. אז לכל נקודה באובייקט אפשר למצוא שלושה ווקטורים ניצבים שאחד מהם הוא הנורמל המקורי בעולם והשניים האחרים פורסים את המישור המשיק. בעזרתם אפשר להעביר בסיס את הנורמל ממפת הנורמלים.
- שיטה לסמלץ השתקפויות של סביבה בזול בעזרת Cube map - בוחרים את הפאה של הקוביה לפי ה-reflection vector של כיוון הצפייה. - פשוט הציר הכי גדול ב-r. (וחיובי או שלילי) - אין השתקפויות של אובייקטים אחרים.
- step(a,x) - smoothstep(a,b,x) - עושה אינטרפולציה קיובית בין 0 ל-1 - f_int(x,y,n) - נותן את האינדקס של הטייל שהנקודה נופלת עליו כשמחלקים את המרחב לn^2 - f_frac(x,y,n) - נותן את המיקום בתא שהנקודה נופלת עליו כשמחלקים את המחרב ל-n^2
בשיידרים אין random, משתמשים בערכים פסאודו אקראיים למשל: $$ frac(\alpha \sin(x)) $$ עבור אלפא גדול כלשהו.
- רעש לבן, לכל x ו-y דוגמים לפי הפונקציה לעיל
- נותן רעש רציף וחלק. - יוצרים גריד, לכל קודקוד בגריד דוגמים לפי הפונקציה הפסאודו אקראית לעיל. ממלאים את החלל עם אינטרפולציה ביליניארית או ביקיובית.
- עושים אינטרפולציה בין גרדיאנטים ולא בין הערכים עצמם. - נראה יותר אורגני. - יוצרים גריד, לכל קודקוד דוגמים שני ערכים שמייצגים ווקטור גרדיאנט. לכל נקודה בחלל, מחשבים את הווקטורים מהפינות אליה, ואז עושים מכפלות פנימיות בין כל ווקטור מפינה לווקטור של הפינה שדגמנו קודם. כך מקבלים ערך בודד לכל פינה, ופשוט עושים אינטרפולציה כמו קודם. - אם להגדיל את הווקטורים שדוגמים כדי להגדיל את העוצמה. - אפשר לעשות כמה שכבות של פרלין עם אמפליטודות שונות כדי לקבל fractal noise.
This topic is covered in: - Lecture 6 (end)
- פונקציה מ-R^3 ל-R. - המרחק הכי קצר מהנקודה לשפת האובייקט. - חיובי כאשר הנקודה מחוץ לאובייקט. - שלילי כאשר הנקודה בתוך האובייקט. - 0 כאשר הנקודה על השפה.
- איחוד: מינימום - לעיתים עושים smooth minimum כדי לקבל פונקציה רציפה - חיתוך: מקסימום - חיסור: $max(f_1 - f_2)$
- דומה ל-Ray casting ברינדור - הגישה הנאיבית היא להתחיל לעשות צעדים בגודל delta לאורך הקרן ולראות אם פגענו באובייקט
- במקום לקחת צעדים בגודל delta קבוע, ניקח צעדים בגודל המרחק לאובייקט הכי קצר. זה מבטיח שלא נפספס אובייקטים וזה יעיל. - מה המרחק הזה? בדיוק הערך של ה-SDF :)
This topic is covered in: - Lecture 7, Lecture 8 - TA 12
- מגדירים עקום באמצעות אוסף נקודות בקרה, ועושים אינטרפולציה ליניארית שוב ושוב ביניהם. - דוגמא במקרה עם שלוש נקודות: - עבור כל $t\in [0,1]$ לוקחים את $\text{lerp}(b_1, b_2, t)$ ואת $\text{lerp}(b_2, b_3, t)$, ואז עושים lerp בין התוצאות עם פרמטר t ומקבלים נקודה אחת בעקום. - אוסף כל הנקודות האלו עבור כל t זה העקום. - בהינתן n+1 נקודות יהיו n שלבי חלוקה, וניתן להוכיח שהקו שמקבלים הוא פולינום ממעלה n. - זה בעצם יוצר עקום Bezier שיש לו נוסחא סגורה (bezier פרסם את זה במקביל). $$ C(t) = \sum_{i=0}^n \binom{n}{i}t^i(1-t)^{n-i}b_i $$ - והמשקולות בפורמולציה של Bezier בעצם נקראים פולינומי ברנשטיין.
- ניתן להוכיח כי בכל רמה הסכום של כל פולינומי ברנשטיין שברמה הזאת הוא 1. - זה מוכיח גאומטרית שתמיד עושים קומבינציה אפינית של נקודות. - כלומר אם עושים טרנספורמציה אפינית רק על נקודות הבקרה ומחשבים מחדש את העקום, זה שקול ללעשות טרנספורמציה ישר על העקום - תכונת הקמור - העקום מוכל בקמור של פוליגון הבקרה (הצורה הקטנה ביותר שנוצרת על ידי קווים ישרים). - אינטרפולציה של נקודות הקצה - כלומר הנקודה הראשונה והאחרונה הן בהכרח חלק מהעקום הנוצר. - סימטריה - ב-t. - אם יש שני עקומים ורוצים לעשות אינטרפולציה ביניהם, אז אפשר פשוט לעשות בין נקודות הבקרה. - שליטה פסאודו לוקאלית - כמות הפעמים שישר חותך את פוליגון הבקרה היא חסם עליון של כמה פעמים ישר חותך את העקום. - העקום משיק לצלע הבקרה הראשונה והאחרונה (לא בהכרח לאחרות) - הנגזרת היא גם עקום בזיאר.
- שקול לעקום בזיאר עם 4 נקודות (מעלה 3). - אבל מוגדר עם שתי נקודות קצה, ושני ווקטורים משיקים.
- במקום לעשות עקומי בזיאר ממעלה גבוהה, לרוב פשוט משרשרים עקומים ממעלה נמוכה. (כי זה יעיל יותר). - נרצה שזה יהיה חלק (גזיר). (כשיש רק עקום אחד הוא גזיר אינסוף פעמים). - הדרך לעשות את זה היא שהמשיק של הסוף של מקטע אחד יהיה באותו כיוון של המשיק של ההתחלה של המקטע השני. - זה גזיר פעם אחת לפחות. (C_1)
- בניגוד לעקום שיש פרמטר אחד, במשטחים יש שני פרמטרים u,v. - בעצם מכפלה של שני פולינומי ברנשטיין שבאחד מציבים u ובשני v. - אם מקבעים פרמטר אחד, מקבלים עקום בזיאר דו מימדי. - את רוב התכונות של עקום ניתן להכליל למשטח.
נעשה תהליך שבו אנו מחלקים את פוליגון הבקרה, והעקום יהיה הגבול של התהליך (נוכיח שמתכנס). נחלק לשתי קבוצות - שיטת מקרבות (approximation): עקום הגבול לא בהכרח עובר דרך נקודות הבקרה - שיטות interpolating: עקום הגבול עובר דרך נקודות הבקרה
רוב השיטות הן בשתי שלבים שחוזרים על עצמם: - מוסיפים קודקודים חדשים (באמצע של כל צלע) - מעדכנים את המיקום של כל הקודקודים על סמך המיקום שלהם והמיקום של השכנים (בקונבולוציה) (ההבדל בין השיטות הוא כאן).
- סכמת subdivision שפועלת לפי מה שכתוב לעיל, כאשר ווקטור המשקולות של הקונבולוציה הוא 0.5,0.5 (ממוצע בין הקודקוד לקודקוד הבא) - שיטה מקרבת
- סכמת subdivision שפועלת לפי מה שכתוב לעיל, כאשר ווקטור המשקולות של הקונבולוציה הוא -1/8, 5/16, 5/8, 5/16 -1/8. בנוסף הקונבולציה פועלת רק על הקודקודים החדשים. - שיטה interpolating - בגלל שיש משקולות שליליות העקום יכול לצאת מהקמור
כדי להראות דוגמת התכנסות, אפשר להשתמש בווקטורים עצמיים וערכים עצמיים. הראינו בכיתה על שיטת עם קונבולוציה 0.25,0.5,0.25.
- אם $v$ הוא הווקטור העצמי השמאלי הראשון ו-$u$ הוא הווקטור העצמי הימני הראשון, אז
$$
u_1 \cdot \sum_{i=0}^n v_i p_i
$$
זאת הנקודה הסופית
- דומה
- מוסיפים קודקוד חדש במרכז של כל פאה, ושל כל קודקוד. מותחים צלעות בין הקודקודים במרכזי הפאות לקודקודים במרכזי הצלעות של הפאה. - (אחרי שלב אחד של חלוקה, כל הפאות הן quads. - שלב המיצוע: - הקודקודים החדשים במרכז כל פאה - מיצוע של הקודקודים המקוריים של הפאה. - הקודקודים החדשים באמצע כל צלע - מיצוע של 4 השכנים שלו (2 שיצרו אותו, ואלו במרכזי פאות שמשני צדדיו) - הקודקודים המקוריים - מיצוע כל השכנים שלו (שהם כולם חדשים - מרכז צלע ומרכז פאה) + המיקום המקורי שלו
This topic is covered in: - Lecture 11
כל הסצנה מיוצגת בעזרת גאוסיאנים. האלגוריתמים הקלאסים של תאורה והסרת משטחים נסתרים לא עובדים באופן נאיבי כי זה לא ממש mesh. גם לא למדנו להתמודד עם אובייקטים שקופים.
- הכלי הקלאסי בגרפיקה להתמודד עם שקיפות חלקית (גם ב-meshes). - לרוב צבעים מיוצג על ידי ווקטור 4 מימדי RGBA. - המשוואה הבסיסית: $$ C = \alpha C_f + (1-\alpha) C_b $$ - אפשר להכליל את זה לסצנה שלמה ולעשות Back to front compositing - מציירים מהרחוק לקרוב ומקבלים משהו שדומה ל-Painter's algorithm, אבל לא עושה override אלא - blending של הנוכחי עם כל מה שהיה לפני. - יש לזה נוסחא סגורה - נשים לב שייתכן שפוליגון קדמי יחסום את כל מה שמאחוריו, גם אם יש שם compositing מורכב, ולכן זה לא ממש יעיל. - אפשר גם לעשות front to back compositing - מתחילים ערך של ״שקיפות שמתחיל ב-1. וכל פעם שמציירים משהו כופלים אותו ב- 1-alpha. - זה נותן בדיוק אותה תוצאה כמו back to front (לא הוכחנו) - אפשר לעצור את החישוב כאשר ערך השקיפות קטן מספיק!
בייצוג גאוסיאן splatting יש לנו פרימטיבים ווליומטרים תלת מימדיים. כלומר יש פשוט פונקציה שמוגדרת בתלת מימד, שאם מציבים בה מספר מקבלים צבע וצפיפות. ואז אפשר לדגום בקו ישר במרחב ולהשתמש בנוסחאת alpha compositing לעיל כדי לחשב את הצבע בכל פיקסל. אפשר לעשות דקומפוזיציה למטריצת הקווריאנס למטריצת רוטציה וסקיילינג על התפלגות נורמלית. אז בפועל באופטימיזציה מוצאים את המספרים האלה.
This topic is covered in: - Lecture 12, Lecture 13
משתמשים בזה למשל לאנימציה של בד, נוזלים, אש.
לצורך סימולציה של בדים, נמדל אותו כמערכת חלקיקים. לכל חלקיק יש מסה ואיזושהי התנהגות בזמן. בבד, החלקיקים יהיו בגריד ויהיו מחוברים בקפיצים. נרצה להבין איך המיקום, המהירות והתאוצה של כל אחד מהחלקיקים משתנה (כל אחד נגזרת של הקודם). אז יש לנו עסק עם משוואות דיפרנציאלות. החוקים הבסיסיים הם חוקי ניוטון. ספציפית החוק השני $F=ma$. והשלישי שאומר שלכל כוח יש כוח שווה ומנוגד.
אז מתקיים: $$F = ma = m \ddot{x}$$ והכוח יכול להשתנות עם הזמן, המיקום והמהירות אז: $$\ddot{x}=\frac{f(x,\dot{x},t)}{m}$$ אבל נפרק את זה לשתי משוואות כי לא אוהבים נגזרת שנייה: $$ \displaylines{ \dot{x} = v \ \dot{v} = \frac{f(x,v,t)}{m} } $$ אנו נמצא פתרון לבעיית ה-initial value problem. כלומר בהנחה שאנחנו יודעים מה המצב של המערכת בהתחלה, ננסה להבין לאן היא תמשיך. קוראים לזה לעשות אינטגרציה. ממה מורכב המצב של כל חלקיק? מיקום, מהירות, כוחות שפועלים עליו (force accumelator), מסה. הסימולציה עצמה היא לולאה על הזמן, עם צעד קטן dt. בכל צעד עושים שני דברים 1. מחשבים את הכוחות על כל אחד מהחלקיקים 1. גרוויטציה $f=mg$, 2. קפיצים - 0 באורך המנוחה, גדל ליניארית במרחק באורך המנוחה כפול קבוע הקפיץ (והכיוון הוא לחלקיק השני או הפוך ממנו). לרוב עושים damping לקפיץ, כלומר חיכוך בשביל יציבות של סימולציה. 3. שדה כוח 4. גרירה (drag) (תלוי מהירות כמו מצנח)) $f=-k_{drag}v$ 2. לפי הכוחות משנים את התאוצה, מהירות, מיקום.
זו בעיית ה-initial value problem. מעתה נתייחס לבעיה הכללית שיש לנו $\dot{x} = f(x,t)$. אנו רוצים להבין איך המיקום ישתנה לאורך זמן, ואנו יכולים לדגום מ-f כל מיקום בזמן הנוכחי (אבל לא מהזמנים הבאים).
השיטה הכי פשוטה. עושים צעדי זמן $\varDelta t = h$ $$ x(t_0 + h) = x(t_0) + h\dot{x}(t_0) $$ - השיטה הזאת קצת בעייתית כי אם לוקחים צעדים גדולים מקבלים שגיאה. - למעשה זה קירוב טיילור מסדר ראשון: $$ x(t+h) = x(t) + h\dot{x}(t) + \frac{h^2}{2!}\ddot{x}(t)+... = x(t) + h\dot{x}(t) + O(h^2) $$ אז השגיאה אמנם מספר קטן אבל היא מצטברת בכל צעד. - יש גם בעיית יציבות. 1/k 2/k 3/k
בכל שלב נשערך את הפונקציה f פעמיים. פעם ראשונה כמו באוילר, ומזה מחשבים $\varDelta x$ ולאחר מכן בפעם השנייה נגדיר: $$ f_{mid}=f(x_0 + \frac{\varDelta x}{2}, t + \frac{h}{2}) $$ ואז: $$ x(t_0 + h) = x(t_0) + h f_{mid} $$ למה? אפשר להראות שזה קירוב טיילור מסדר 2. כלומר: $$ f_{mid} \approx \dot{x}(t) + \frac{h^2}{2!}\ddot{x}(t) $$
שיפור כללי לשיטה שעוזר לבחור את צעד הזמן. בכל שלב משערכים לפי צעד הזמן, ולפי חצי מצעד זמן. אם ההבדל גדול מסף מסוים, מורידים את צעד הזמן.
- במקום לחשב את $x_{new} = x(t_0) + h\dot{x}(t_0)$, נחשב את $x_{new} = x(t_0) + h\dot{x}(t + h)$ - זה כמו לקחת טור טיילור סביב הנקודה t+h: $$ x(t) = x(t+h) - h\dot{x}(t+h) + O(h^2) x(t+h) = x(t) + h\dot{x}(t+h) + O(h^2) $$ - אז איך מוצאים את $h\dot{x}(t+h)$? פיתוח מתמטי די ארוך אבל לסיכום מתקיים: $$ \varDelta x = h(I - hf'(x_0))^{-1}f(x_0) $$ - אפשר להוכיח שזה יותר יציב מאוילר הרגיל.
1. שיטה עם שלושה סוגים של קפיצים על גריד, בין כל שכן, דילוג על שכן אלכסוני ודילוג על שכן הוריזונטלי/וורטיקלי. 2. שיטת baraff-witkin