diff --git a/exam-2/10a.jpg b/exam-2/10a.jpg new file mode 100644 index 000000000..b100256 Binary files /dev/null and b/exam-2/10a.jpg differ diff --git a/exam-2/10b.jpg b/exam-2/10b.jpg new file mode 100644 index 000000000..6e055bc Binary files /dev/null and b/exam-2/10b.jpg differ diff --git a/exam-2/7a.blend b/exam-2/7a.blend new file mode 100644 index 000000000..0f1e34b Binary files /dev/null and b/exam-2/7a.blend differ diff --git a/exam-2/7a.jpg b/exam-2/7a.jpg new file mode 100644 index 000000000..3c27e7c Binary files /dev/null and b/exam-2/7a.jpg differ diff --git a/exam-2/7b.blend b/exam-2/7b.blend new file mode 100644 index 000000000..cb5813c Binary files /dev/null and b/exam-2/7b.blend differ diff --git a/exam-2/7b.blend1 b/exam-2/7b.blend1 new file mode 100644 index 000000000..9e50455 Binary files /dev/null and b/exam-2/7b.blend1 differ diff --git a/exam-2/7b.jpg b/exam-2/7b.jpg new file mode 100644 index 000000000..0a6400e Binary files /dev/null and b/exam-2/7b.jpg differ diff --git a/exam-2/7c.blend b/exam-2/7c.blend new file mode 100644 index 000000000..0d8c81a Binary files /dev/null and b/exam-2/7c.blend differ diff --git a/exam-2/7c.blend1 b/exam-2/7c.blend1 new file mode 100644 index 000000000..4acf7f8 Binary files /dev/null and b/exam-2/7c.blend1 differ diff --git a/exam-2/7c.jpg b/exam-2/7c.jpg new file mode 100644 index 000000000..9307f47 Binary files /dev/null and b/exam-2/7c.jpg differ diff --git a/exam-2/exam2.md b/exam-2/exam2.md index 08acec7..002fe96 100644 --- a/exam-2/exam2.md +++ b/exam-2/exam2.md @@ -14,20 +14,20 @@ author: | \newcommand{\now}[1]{\textcolor{blue}{#1}} \newcommand{\todo}[0]{\textcolor{red}{\textbf{TODO}}} -[ 1 2 3 4 6 7 8 9 10 ] +[ 1 2 3 6 8 9 ] ## Reflection and Refraction -1. \c{Consider a sphere $S$ made of solid glass ($\eta$ = 1.5) that has radius $r = - 3$ and is centered at the location $s = (2, 2, 10)$ in a vaccum ($\eta = +1. \c{Consider a sphere $S$ made of solid glass ($\eta$ = 1.5) that has radius + $r = 3$ and is centered at the location $s = (2, 2, 10)$ in a vaccum ($\eta = 1.0$). If a ray emanating from the point $e = (0, 0, 0)$ intersects $S$ at a point $p = (1, 4, 8)$:} a. \c{(2 points) What is the angle of incidence $\theta_i$?} - The incoming ray is in the direction $I = p - e = (1, 4, 8)$, and the normal at - that point is $N = p - s = (1, 4, 8) - (2, 2, 10) = (1, -2, 2)$. The angle can - be found by taking the opposite of the incoming ray $-I$ and using the + The incoming ray is in the direction $I = p - e = (1, 4, 8)$, and the normal + at that point is $N = p - s = (1, 4, 8) - (2, 2, 10) = (1, -2, 2)$. The angle + can be found by taking the opposite of the incoming ray $-I$ and using the formula $\cos \theta_i = \frac{-I \cdot N}{|I| |N|} = \frac{(-1, -4, -8) \cdot (1, -2, 2)}{9 \cdot 3} = \frac{-1 + 8 - 16}{27} = -\frac{1}{3}$. So the angle $\boxed{\theta_i = \cos^{-1}(-\frac{1}{3})}$. @@ -198,21 +198,45 @@ author: | pointing in the direction $(1, -1, -1)$, and the camera's 'up' direction is $(0, 1, 0)$, what are the entries in $V$?} - First we can calculate $n$ and $u$: - - Viewing direction is $(1, -1, -1)$. - Normalized $n = (\frac{1}{\sqrt{3}}, -\frac{1}{\sqrt{3}}, -\frac{1}{\sqrt{3}})$. - - $u = up \times n = (-\frac{1}{\sqrt{2}}, 0, -\frac{1}{\sqrt{2}})$. - - $v = n \times u = (\frac{\sqrt{6}}{6}, \frac{\sqrt{6}}{3}, -\frac{\sqrt{6}}{6})$ + - $u = up \times n = (\frac{1}{\sqrt{2}}, 0, \frac{1}{\sqrt{2}})$. + - $v = n \times u = (\frac{\sqrt{6}}{6}, \frac{2}{\sqrt{6}}, -\frac{\sqrt{6}}{6})$ + - $d_x = - (eye \cdot u) = - (2 \times \frac{1}{\sqrt{2}} + 5 \times \frac{1}{\sqrt{2}}) = -\frac{7}{\sqrt{2}}$ + - $d_y = - (eye \cdot v) = - (2 \times \frac{1}{\sqrt{6}} + 3 \times + \frac{2}{\sqrt{6}} - 5 \times \frac{1}{\sqrt{6}}) = -\frac{3}{\sqrt{6}}$ + - $d_z = - (eye \cdot n) = - (2 \times \frac{1}{\sqrt{3}} - 3 \times + \frac{1}{\sqrt{3}} - 5 \times \frac{1}{\sqrt{3}}) = -\frac{6}{\sqrt{3}}$ $$ \begin{bmatrix} - -\frac{1}{\sqrt{2}} & 0 & -\frac{1}{\sqrt{2}} & d_x \\ - 1 & -1 & -1 & d_y \\ + \frac{1}{\sqrt{2}} & 0 & \frac{1}{\sqrt{2}} & -\frac{7}{\sqrt{2}} \\ + \frac{1}{\sqrt{6}} & \frac{2}{\sqrt{6}} & -\frac{1}{\sqrt{6}} & -\frac{3}{\sqrt{6}} \\ + -\frac{1}{\sqrt{3}} & \frac{1}{\sqrt{3}} & \frac{1}{\sqrt{3}} & -\frac{6}{\sqrt{3}} \\ + 0 & 0 & 0 & 1 \\ \end{bmatrix} $$ - \todo + Also solved using a Python script: + + ```py + def view_matrix(camera_pos, view_dir, up_dir): + n = unit(-view_dir) + u = unit(np.cross(up_dir, n)) + v = np.cross(n, u) + return np.array([ + [u[0], u[1], u[2], -np.dot(camera_pos, u)], + [v[0], v[1], v[2], -np.dot(camera_pos, v)], + [n[0], n[1], n[2], -np.dot(camera_pos, n)], + [0, 0, 0, 1], + ]) + + camera_pos = np.array([2, 3, 5]) + view_dir = np.array([1, -1, -1]) + up_dir = np.array([0, 1, 0]) + V = view_matrix(camera_pos, view_dir, up_dir) + print(V) + ``` b. \c{(2 points) How will this matrix change if the eye moves forward in the direction of view? [which elements in V will stay the same? which elements @@ -346,39 +370,253 @@ author: | 6. \c{Consider a cube of width $2\sqrt{3}$ centered at the point $(0, 0, -3\sqrt{3})$, whose faces are colored light grey on the top and bottom $(y = - \pm\sqrt{3})$, dark grey on the front and back $(z = -2\sqrt{3} \textrm{and} - z = -4\sqrt{3})$, red on the right $(x = \sqrt{3})$, and green on the left $(x - = -\sqrt{3})$.} + \pm\sqrt{3})$, dark grey on the front and back ($z = -2\sqrt{3}$ and $z = + -4\sqrt{3}$), red on the right $(x = \sqrt{3})$, and green on the left $(x = + -\sqrt{3})$.} a. \c{Show how you could project the vertices of this cube to the plane $z = 0$ using an orthographic parallel projection:} - i) \c{(2 points) Where will the six vertex locations be after such a - projection, omitting the normalization step?} + i) \c{(2 points) Where will the six vertex locations be after such a + projection, omitting the normalization step?} - ii) \c{(1 points) Sketch the result, being as accurate as possible and - labeling the colors of each of the visible faces.} + - $[\begin{matrix}-1.732 & -1.732 & -6.928\end{matrix}]$ $\rightarrow$ $[\begin{matrix}-1.0 & -1.0 & 7.0\end{matrix}]$ + - $[\begin{matrix}-1.732 & -1.732 & -3.464\end{matrix}]$ $\rightarrow$ $[\begin{matrix}-1.0 & -1.0 & 5.0\end{matrix}]$ + - $[\begin{matrix}-1.732 & 1.732 & -6.928\end{matrix}]$ $\rightarrow$ $[\begin{matrix}-1.0 & 1.0 & 7.0\end{matrix}]$ + - $[\begin{matrix}-1.732 & 1.732 & -3.464\end{matrix}]$ $\rightarrow$ $[\begin{matrix}-1.0 & 1.0 & 5.0\end{matrix}]$ + - $[\begin{matrix}1.732 & -1.732 & -6.928\end{matrix}]$ $\rightarrow$ $[\begin{matrix}1.0 & -1.0 & 7.0\end{matrix}]$ + - $[\begin{matrix}1.732 & -1.732 & -3.464\end{matrix}]$ $\rightarrow$ $[\begin{matrix}1.0 & -1.0 & 5.0\end{matrix}]$ + - $[\begin{matrix}1.732 & 1.732 & -6.928\end{matrix}]$ $\rightarrow$ $[\begin{matrix}1.0 & 1.0 & 7.0\end{matrix}]$ + - $[\begin{matrix}1.732 & 1.732 & -3.464\end{matrix}]$ $\rightarrow$ $[\begin{matrix}1.0 & 1.0 & 5.0\end{matrix}]$ - iii) \c{(2 points) Show how you could achieve this transformation using one or - more matrix multiplication operations. Specify the matrix entries you would - use, and, if using multiple matrices, the order in which they would be - multiplied.} + ii) \c{(1 points) Sketch the result, being as accurate as possible and + labeling the colors of each of the visible faces.} - b. Show how you could project the vertices of this cube to the plane $z = 0$ - using an oblique parallel projection in the direction $d = (1, 0, \sqrt{3})$: + This is just a square with the dark gray side facing the camera. The other + sides are not visible because the cube is parallel to the axis, and when you + do an orthographic projection, those faces are lost. - i) (3 points) Where will the six vertex locations be after such a projection, - omitting the normalization step? + iii) \c{(2 points) Show how you could achieve this transformation using one or + more matrix multiplication operations. Specify the matrix entries you would + use, and, if using multiple matrices, the order in which they would be + multiplied.} - ii) (2 points) Sketch the result, being as accurate as possible and labeling - the colors of each of the visible faces. + Actually, I got the numbers above by using the three transformation matrices + in this Python script: - iii) (4 points) Show how you could achieve this transformation using one or - more matrix multiplication operations. Specify the matrix entries you would - use, and, if using multiple matrices, the order in which they would be - multiplied. + ```py + def ortho(points): + left = min(map(lambda p: p[0], points)) + right = max(map(lambda p: p[0], points)) + bottom = min(map(lambda p: p[1], points)) + top = max(map(lambda p: p[1], points)) + near = min(map(lambda p: p[2], points)) + far = max(map(lambda p: p[2], points)) -7. + step_1 = np.array([ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, -1, 0], + [0, 0, 0, 1], + ]) + + step_2 = np.array([ + [1, 0, 0, -(left + right) / 2.0], + [0, 1, 0, -(bottom + top) / 2.0], + [0, 0, 1, -(near + far) / 2.0], + [0, 0, 0, 1], + ]) + + step_3 = np.array([ + [2.0 / (right - left), 0, 0, 0], + [0, 2.0 / (top - bottom), 0, 0], + [0, 0, 2.0 / (far - near), 0], + [0, 0, 0, 1], + ]) + + M_ortho = step_3 @ step_2 @ step_1 + ``` + + b. \c{Show how you could project the vertices of this cube to the plane $z = + 0$ using an oblique parallel projection in the direction $d = (1, 0, + \sqrt{3})$:} + + i) \c{(3 points) Where will the six vertex locations be after such a + projection, omitting the normalization step?} + + ii) \c{(2 points) Sketch the result, being as accurate as possible and + labeling the colors of each of the visible faces.} + + iii) \c{(4 points) Show how you could achieve this transformation using one + or more matrix multiplication operations. Specify the matrix entries you + would use, and, if using multiple matrices, the order in which they would be + multiplied.} + +7. \c{Consider the simple scene shown in the image below, where two cubes, one + of height 1 and one of height 2, are both resting on a horizontal groundplane + ($y = -\frac{1}{2}$), with the smaller cube’s front face aligned with $z = + -4$ and the larger cube’s front face aligned with $z = -7$.} + + a. \c{(5 points) Let the camera location be (0, 0, 0), looking down the $-z$ + axis, with the field of view set at $90^\circ$. Determine the points, in the + image plane, to which each of the cube vertices will be projected and sketch + the result to scale. Please clearly label the coordinates to avoid + ambiguity.} + + For this part, I reimplemented the perspective rendering algorithm using + Python. + + ```py + def perspective_matrix(left, right, bottom, top, near, far): + return np.array([ + [2.0 * near / (right - left), 0, (right + left) / (right - left), 0], + [0, 2.0 * near / (top - bottom), (top + bottom) / (top - bottom), 0], + [0, 0, -(far + near) / (far - near), -(2.0 * far * near) / (far - near)], + [0, 0, -1, 0], + ]) + + def view_matrix(camera_pos, view_dir, up_dir): + n = unit(-view_dir) + u = unit(np.cross(up_dir, n)) + v = np.cross(n, u) + return np.array([ + [u[0], u[1], u[2], -np.dot(camera_pos, u)], + [v[0], v[1], v[2], -np.dot(camera_pos, v)], + [n[0], n[1], n[2], -np.dot(camera_pos, n)], + [0, 0, 0, 1], + ]) + ``` + + The perspective and view matrices are: + + $$ + PV = + \begin{bmatrix} + 1.0 & 0.0 & 0.0 & 0.0 \\ + 0.0 & 1.0 & 0.0 & 0.0 \\ + 0.0 & 0.0 & -1.2222 & -2.2222 \\ + 0.0 & 0.0 & -1.0 & 0.0 \\ + \end{bmatrix} + \begin{bmatrix} + 1.0 & 0.0 & 0.0 & -0.0 \\ + 0.0 & 1.0 & 0.0 & -0.0 \\ + 0.0 & 0.0 & 1.0 & -0.0 \\ + 0.0 & 0.0 & 0.0 & 1.0 \\ + \end{bmatrix} + $$ + + Then I ran the transformation using the data given in this particular scene: + + ```py + def compute_view(near, vfov, hfov): + left = -math.tan(hfov / 2.0) * near + right = math.tan(hfov / 2.0) * near + bottom = -math.tan(vfov / 2.0) * near + top = math.tan(vfov / 2.0) * near + return left, right, bottom, top + + def solve(camera_pos, angle): + angle_radians = math.radians(angle) + near = 1 + far = 10 + view_dir = np.array([0, 0, -1]) + up_dir = np.array([0, 1, 0]) + left, right, bottom, top = compute_view(near, angle_radians, angle_radians) + P = perspective_matrix(left, right, bottom, top, near, far) + V = view_matrix(camera_pos, view_dir, up_dir) + return P @ V + + camera_pos = np.array([0, 0, 0]) + angle = 90 + m = np.around(solve(camera_pos, angle), 4) + ``` + + This performed the transformation on the front face of the small cube: + + - $[\begin{matrix}0.5 & 0.5 & -4.0\end{matrix}]$ $\rightarrow$ $[\begin{matrix}0.5 & 0.5 & 2.6666\end{matrix}]$ + - $[\begin{matrix}0.5 & -0.5 & -4.0\end{matrix}]$ $\rightarrow$ $[\begin{matrix}0.5 & -0.5 & 2.6666\end{matrix}]$ + - $[\begin{matrix}-0.5 & -0.5 & -4.0\end{matrix}]$ $\rightarrow$ $[\begin{matrix}-0.5 & -0.5 & 2.6666\end{matrix}]$ + - $[\begin{matrix}-0.5 & 0.5 & -4.0\end{matrix}]$ $\rightarrow$ $[\begin{matrix}-0.5 & 0.5 & 2.6666\end{matrix}]$ + + and this transformation on the front face of the large cube: + + - $[\begin{matrix}1.0 & 1.5 & -7.0\end{matrix}]$ $\rightarrow$ $[\begin{matrix}1.0 & 1.5 & 6.3332\end{matrix}]$ + - $[\begin{matrix}1.0 & -0.5 & -7.0\end{matrix}]$ $\rightarrow$ $[\begin{matrix}1.0 & -0.5 & 6.3332\end{matrix}]$ + - $[\begin{matrix}-1.0 & -0.5 & -7.0\end{matrix}]$ $\rightarrow$ $[\begin{matrix}-1.0 & -0.5 & 6.3332\end{matrix}]$ + - $[\begin{matrix}-1.0 & 1.5 & -7.0\end{matrix}]$ $\rightarrow$ $[\begin{matrix}-1.0 & 1.5 & 6.3332\end{matrix}]$ + + Here's a render using Blender: + + ![](7a.jpg){width=40%} + + b. \c{(4 points) How would the image change if the camera were moved forward by + 2 units, leaving all of the other parameter settings the same? Determine the + points, in the image plane, to which each of the cube vertices would be + projected in this case and sketch the result to scale. Please clearly label + the coordinates to avoid ambiguity.} + + Here is the updated Blender render: + + ![](7b.jpg){width=40%} + + As you can see, the cubes now take up more of the frame, and in particular + the red cube has been warped to take up more camera width than the blue. + + c. \c{(4 points) How would the image change if, instead of moving the camera, + the field of view were reduced by half, to $45^\circ$, leaving all of the + other parameter settings the same? Determine the points, in the image plane, + to which each of the cube vertices would be projected and sketch the result + to scale. Please clearly label the coordinates to avoid ambiguity.} + + Here is the updated Blender render: + + ![](7c.jpg){width=40%} + + Because of the reduced FOV, there is less of the scene shown so the cubes + take up more of the view. However, there is less of the perspective + foreshortening effect, so the front cube doesn't get warped into being wider + or bigger than the back cube. + + d. (2 points) + + - \c{Briefly describe what you notice.} + + The cubes aren't warped except when they change distance from the eye. + + - \c{When looking at two cube faces that are equal sizes in reality (e.g. front + and back) does one appear smaller than the other when one is more distant + from the camera than the other?} + + Yes. + + - \c{When looking at two objects that are resting on a common horizontal + groundplane, does the groundplane appear to be tiled in the image, so that + the objects that are farther away appear to be resting on a base that is + higher as their distance from the camera increases?} + + Yes. + + - \c{What changes do you observe in the relative heights, in the image, of the + smaller and larger cubes as the camera position changes?} + + When the camera position is closer to the cubes, the front cube takes up + more space overall and so it takes up more height as well. But once the + camera is far, the big cube has a bigger relative height since their + heights aren't really warped from each other anymore. + + - \c{Is there a point at which the camera could be so close to the smaller cube + (but not touching it) that the larger cube would be completely obscured in + the camera’s image?} + + Yes. You can imagine that if the camera was a microscopically small + distance from the front cube (and the $near$ value was also small enough to + accommodate!), then the front cube would take up the entire image. + + - \c{Based on these insights, what can you say about the idea to create an + illusion of "getting closer" to an object in a photographed scene by + zooming in on the image and cropping it so that the object looks bigger?} + + It's not entirely accurate, because of perspective warp. 8. \c{Consider the perspective projection-normalization matrix $P$ which maps the contents of the viewing frustum into a cube that extends from -1 to 1 in @@ -477,11 +715,24 @@ author: | - \c{After the six vertices v0 .. v5 are sent to be clipped, what will the vertex list be after clipping process has finished?} + ![](10a.jpg){width=40%} + - \c{How can this new result be expressed as a triangle strip? (Try to be as efficient as possible)} + The only way to get this to be represented as a triangle strip is to + change around the some of the existing lines. Otherwise, the order of the + vertices prevents the exact same configuration from working. + + See below for a working version (only consider the green lines, ignore the + red lines): + + ![](10b.jpg){width=40%} + - \c{How many triangles will be encoded in the clipped triangle strip?} + Based on the image above, 8 triangles will be used. + ## Ray Tracing vs Scan Conversion 11. \c{(8 points) List the essential steps in the scan-conversion (raster diff --git a/exam-2/exam2.py b/exam-2/exam2.py index ffacc45..2acc6ef 100644 --- a/exam-2/exam2.py +++ b/exam-2/exam2.py @@ -1,136 +1,290 @@ +import itertools import numpy as np from sympy import * import math unit = lambda v: v/np.linalg.norm(v) +def perspective_matrix(vfov, width, height, left, right, bottom, top, near, far): + aspect = width / height + return np.array([ + [1.0 / math.tan(vfov / 2.0) / aspect, 0, 0, 0], + [0, 1.0 / math.tan(vfov / 2.0), 0, 0], + [0, 0, -(far + near) / (far - near), -2.0 * far * near / (far - near)], + [0, 0, -1, 0] + ]) + # return np.array([ + # [2.0 * near / (right - left), 0, (right + left) / (right - left), 0], + # [0, 2.0 * near / (top - bottom), (top + bottom) / (top - bottom), 0], + # [0, 0, -(far + near) / (far - near), -(2.0 * far * near) / (far - near)], + # [0, 0, -1, 0], + # ]) + +def view_matrix(camera_pos, view_dir, up_dir): + n = unit(-view_dir) + u = unit(np.cross(up_dir, n)) + v = np.cross(n, u) + return np.array([ + [u[0], u[1], u[2], -np.dot(camera_pos, u)], + [v[0], v[1], v[2], -np.dot(camera_pos, v)], + [n[0], n[1], n[2], -np.dot(camera_pos, n)], + [0, 0, 0, 1], + ]) + +def print_trans(before, after): + def style_vec(v): + start = "$[\\begin{matrix}" + mid = str(v[0]) + " & " + str(v[1]) + " & " + str(v[2]) + end = "\\end{matrix}]$" + return f"{start}{mid}{end}" + return style_vec(before) + " $\\rightarrow$ " + style_vec(after) + +def compute_view(near, vfov, hfov): + width = 2.0 * near * math.tan(hfov / 2.0) + height = 2.0 * near * math.tan(hfov / 2.0) + + left = -width / 2.0 + right = width / 2.0 + bottom = -height / 2.0 + top = height / 2.0 + return width, height, left, right, bottom, top + +def print_bmatrix(arr): + for row in arr: + for j, col in enumerate(row): + end = " " if j == len(row) - 1 else " & " + print(col, end=end) + print("\\\\") + def problem_1(): - p = np.array([1, 4, 8]) - e = np.array([0, 0, 0]) - s = np.array([2, 2, 10]) + p = np.array([1, 4, 8]) + e = np.array([0, 0, 0]) + s = np.array([2, 2, 10]) - i = p - e - print("incoming", i) - print("|I| =", np.linalg.norm(i)) - n = s - p - print("normal", n) + i = p - e + print("incoming", i) + print("|I| =", np.linalg.norm(i)) + n = s - p + print("normal", n) - n_norm = unit(n) - print("normal_norm", n_norm) - cos_theta_i = np.dot(-i, n) / (np.linalg.norm(i) * np.linalg.norm(n)) - print("part a = cos^{-1} of ", cos_theta_i) - print(np.arccos(cos_theta_i)) + n_norm = unit(n) + print("normal_norm", n_norm) + cos_theta_i = np.dot(-i, n) / (np.linalg.norm(i) * np.linalg.norm(n)) + print("part a = cos^{-1} of ", cos_theta_i) + print(np.arccos(cos_theta_i)) - proj = n_norm * np.linalg.norm(i) * cos_theta_i - print("proj", proj) + proj = n_norm * np.linalg.norm(i) * cos_theta_i + print("proj", proj) - p_ = p + proj - print("proj point", p_) + p_ = p + proj + print("proj point", p_) - v2 = p_ - e - print("v2", v2) + v2 = p_ - e + print("v2", v2) - sin_theta_i = np.sin(np.arccos(cos_theta_i)) - print("sin theta_i =", sin_theta_i) + sin_theta_i = np.sin(np.arccos(cos_theta_i)) + print("sin theta_i =", sin_theta_i) - theta_t = np.arcsin(1.0 / 1.5 * sin_theta_i) - print("approx answer for part d", theta_t) + theta_t = np.arcsin(1.0 / 1.5 * sin_theta_i) + print("approx answer for part d", theta_t) - uin = unit(n_norm) - print("unit inv normal", uin) + uin = unit(n_norm) + print("unit inv normal", uin) - uperp = unit(v2) - print("uperp", uperp) + uperp = unit(v2) + print("uperp", uperp) - answer_1e = uin + math.tan(theta_t) * uperp - p - print("1e answer", unit(answer_1e)) + answer_1e = uin + math.tan(theta_t) * uperp - p + print("1e answer", unit(answer_1e)) def problem_4(): - print("part 4a.") - up = np.array([0, 1, 0]) - viewing_dir = np.array([1, -1, -1]) - n = unit(viewing_dir) - print(f"{n = }") + camera_pos = np.array([2, 3, 5]) + view_dir = np.array([1, -1, -1]) + up_dir = np.array([0, 1, 0]) + V = view_matrix(camera_pos, view_dir, up_dir) + print(V) - u = unit(np.cross(up, n)) - print(f"{u = }") + f = np.vectorize(lambda c: (c * c)) + print(f(V)) - v = np.cross(n, u) - print(f"{v = }") - - print(math.sqrt(1 / 6.0)) - print(math.sqrt(2 / 3.0)) def build_translation_matrix(vec): - return np.array([ - [1, 0, 0, vec[0]], - [0, 1, 0, vec[1]], - [0, 0, 1, vec[2]], - [0, 0, 0, 1], - ]) + return np.array([ + [1, 0, 0, vec[0]], + [0, 1, 0, vec[1]], + [0, 0, 1, vec[2]], + [0, 0, 0, 1], + ]) def problem_5(): - b1 = build_translation_matrix(np.array([0, 0, 5])) - theta = math.radians(-90) - sin_theta = round( math.sin(theta), 5) - cos_theta = round(math.cos(theta), 5) - b2 = np.array([ - [cos_theta, 0, sin_theta, 0], - [0, 1, 0, 0], - [-sin_theta, 0, cos_theta, 0], - [0, 0, 0, 1], - ]) - b3 = build_translation_matrix(np.array([0, 0, -5])) + b1 = build_translation_matrix(np.array([0, 0, 5])) + theta = math.radians(-90) + sin_theta = round( math.sin(theta), 5) + cos_theta = round(math.cos(theta), 5) + b2 = np.array([ + [cos_theta, 0, sin_theta, 0], + [0, 1, 0, 0], + [-sin_theta, 0, cos_theta, 0], + [0, 0, 0, 1], + ]) + b3 = build_translation_matrix(np.array([0, 0, -5])) - print("b1", b1) - print("b2", b2) - print("b3", b3) - M = b3 @ b2 @ b1 - print("M", M) + print("b1", b1) + print("b2", b2) + print("b3", b3) + M = b3 @ b2 @ b1 + print("M", M) - ex1 = np.array([1, 1, -4, 1]) - print("ex1", ex1, M @ ex1) + ex1 = np.array([1, 1, -4, 1]) + print("ex1", ex1, M @ ex1) - up = np.array([0, 1, 0]) - n = np.array([1, 0, 0]) - u = unit(np.cross(up, n)) - v = np.cross(n, u) + up = np.array([0, 1, 0]) + n = np.array([1, 0, 0]) + u = unit(np.cross(up, n)) + v = np.cross(n, u) - print(f"{up = }, {n = }, {u = }, {v = }") + print(f"{up = }, {n = }, {u = }, {v = }") - eye = np.array([5, 0, -5]) - dx = -(np.dot(eye, u)) - dy = -(np.dot(eye, v)) - dz = -(np.dot(eye, n)) - print(f"{dx = }, {dy = }, {dz = }") + eye = np.array([5, 0, -5]) + dx = -(np.dot(eye, u)) + dy = -(np.dot(eye, v)) + dz = -(np.dot(eye, n)) + print(f"{dx = }, {dy = }, {dz = }") def problem_8(): - def P(left, right, bottom, top, near, far): - return np.array([ - [2.0 * near / (right - left), 0, (right + left) / (right - left), 0], - [0, 2.0 * near / (top - bottom), (top + bottom) / (top - bottom), 0], - [0, 0, -(far + near) / (far - near), -(2.0 * far * near) / (far - near)], - [0, 0, -1, 0], - ]) - - near = 0.5 - far = 20 - - def compute_view(vfov, hfov): - left = -math.tan(hfov) * near - right = math.tan(hfov) * near - bottom = -math.tan(vfov) * near - top = math.tan(vfov) * near - return left, right, bottom, top + near = 0.5 + far = 20 - print("part 8a") - vfov = hfov = math.radians(60) - left, right, bottom, top = compute_view(vfov, hfov) - print(P(left, right, bottom, top, near, far)) - print() -print("\nPROBLEM 4 -------------------------"); problem_4() + print("part 8a") + vfov = hfov = math.radians(60) + width, height, left, right, bottom, top = compute_view(near, vfov, hfov) + print(perspective_matrix(vfov, width, height, left, right, bottom, top, near, far)) + print() + +def problem_7(): + + def solve(camera_pos, angle): + angle_radians = math.radians(angle) + near = 1 + far = 10 + view_dir = np.array([0, 0, -1]) + up_dir = np.array([0, 1, 0]) + width, height, left, right, bottom, top = compute_view(near, angle_radians, angle_radians) + print("faces of the viewing frustum", left, right, bottom, top) + P = perspective_matrix(angle_radians, width, height, left, right, bottom, top, near, far) + V = view_matrix(camera_pos, view_dir, up_dir) + print("P") + print_bmatrix(np.around(P, 4)) + print("V") + print_bmatrix(np.around(V, 4)) + m = P @ V + + points = [ + np.array([0.5, 0.5, -4]), + np.array([0.5, -0.5, -4]), + np.array([-0.5, -0.5, -4]), + np.array([-0.5, 0.5, -4]), + + np.array([0.5, 0.5, -5]), + np.array([0.5, -0.5, -5]), + np.array([-0.5, -0.5, -5]), + np.array([-0.5, 0.5, -5]), + + np.array([1, 1.5, -7]), + np.array([1, -0.5, -7]), + np.array([-1, -0.5, -7]), + np.array([-1, 1.5, -7]), + + np.array([1, 1.5, -9]), + np.array([1, -0.5, -9]), + np.array([-1, -0.5, -9]), + np.array([-1, 1.5, -9]), + ] + + for point in points: + point_ = np.r_[point, [1]] + trans = m @ point_ + def style_vec(v): + start = "$[\\begin{matrix}" + mid = str(v[0]) + " & " + str(v[1]) + " & " + str(v[2]) + end = "\\end{matrix}]$" + return f"{start}{mid}{end}" + print("-", style_vec(point), "$\\rightarrow$", style_vec(np.around(trans[:3], 4))) + + print("Part A") + camera_pos = np.array([0, 0, 0]) + angle = 90 + solve(camera_pos, angle) + + print("Part B") + camera_pos = np.array([0, 0, -2]) + angle = 90 + solve(camera_pos, angle) + + print("Part C") + camera_pos = np.array([0, 0, 0]) + angle = 45 + solve(camera_pos, angle) + +def problem_6(): + def calculate(points): + left = min(map(lambda p: p[0], points)) + right = max(map(lambda p: p[0], points)) + bottom = min(map(lambda p: p[1], points)) + top = max(map(lambda p: p[1], points)) + near = min(map(lambda p: p[2], points)) + far = max(map(lambda p: p[2], points)) + + step_1 = np.array([ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, -1, 0], + [0, 0, 0, 1], + ]) + + step_2 = np.array([ + [1, 0, 0, -(left + right) / 2.0], + [0, 1, 0, -(bottom + top) / 2.0], + [0, 0, 1, -(near + far) / 2.0], + [0, 0, 0, 1], + ]) + + step_3 = np.array([ + [2.0 / (right - left), 0, 0, 0], + [0, 2.0 / (top - bottom), 0, 0], + [0, 0, 2.0 / (far - near), 0], + [0, 0, 0, 1], + ]) + + M_ortho = step_3 @ step_2 @ step_1 + + for point in points: + point_ = np.r_[point, [1]] + trans_ = M_ortho @ point_ + trans = trans_[:3] + print("-", print_trans(np.around(point, 3), np.around(trans, 3))) + + sqrt3 = math.sqrt(3) + width = 2.0 * sqrt3 + cube_center = np.array([0, 0, -3.0 * sqrt3]) + print("HELLOSU") + + points = [] + for (dx, dy, dz) in itertools.product([-1, 1], [-1, 1], [-1, 1]): + point = cube_center + np.array([dx * width / 2, dy * width / 2, dz * width / 2]) + points.append(point) + + calculate(points) + +def problem_9(): + pass + print("\nPROBLEM 8 -------------------------"); problem_8() print("\nPROBLEM 1 -------------------------"); problem_1() print("\nPROBLEM 5 -------------------------"); problem_5() +print("\nPROBLEM 9 -------------------------"); problem_9() +print("\nPROBLEM 7 -------------------------"); problem_7() +print("\nPROBLEM 6 -------------------------"); problem_6() +print("\nPROBLEM 4 -------------------------"); problem_4()