{"id":48754345,"url":"https://github.com/GregStanton/webgl2-glsl-primer","last_synced_at":"2026-04-28T21:00:53.688Z","repository":{"id":328084100,"uuid":"1112836596","full_name":"GregStanton/webgl2-glsl-primer","owner":"GregStanton","description":"Grok WebGL2 and GLSL through spaced repetition and hands-on projects. A zero-to-hero guide covering the programmable geometry pipeline, state management, and 3D shader logic.","archived":false,"fork":false,"pushed_at":"2026-03-24T02:44:20.000Z","size":627,"stargazers_count":60,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-25T02:39:40.644Z","etag":null,"topics":["creative-coding","educational-resources","glsl","graphics-programming","spaced-repetition","webgl2"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GregStanton.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-09T06:59:33.000Z","updated_at":"2026-03-24T02:44:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/GregStanton/webgl2-glsl-primer","commit_stats":null,"previous_names":["gregstanton/webgl2-glsl-primer"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/GregStanton/webgl2-glsl-primer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GregStanton%2Fwebgl2-glsl-primer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GregStanton%2Fwebgl2-glsl-primer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GregStanton%2Fwebgl2-glsl-primer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GregStanton%2Fwebgl2-glsl-primer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GregStanton","download_url":"https://codeload.github.com/GregStanton/webgl2-glsl-primer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GregStanton%2Fwebgl2-glsl-primer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32399010,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T19:38:08.556Z","status":"ssl_error","status_checked_at":"2026-04-28T19:37:55.688Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["creative-coding","educational-resources","glsl","graphics-programming","spaced-repetition","webgl2"],"created_at":"2026-04-13T00:00:50.014Z","updated_at":"2026-04-28T21:00:53.675Z","avatar_url":"https://github.com/GregStanton.png","language":null,"funding_links":[],"categories":["WebGL 2"],"sub_categories":["Tutorials"],"readme":"# WebGL2 \u0026 GLSL primer: \u003cbr /\u003e A zero-to-hero, spaced-repetition guide\n\n**Status:** Complete  \n**Author:** Greg Stanton\n\nThis primer takes the reader from _zero_ (no knowledge of WebGL2 or GLSL) to _hero_ (confidence in everything from low-level state management to procedural graphics production). If you want to engineer advanced 2D or 3D graphics, or understand how graphics are implemented under the hood, then this guide is for you.\n\n## :brain: Method\nFundamentals of WebGL2 and GLSL are introduced in a natural order, chunking concepts and syntax into atomic Q\u0026A _cards_. But **this is _not_ a typical FAQ or a cheat sheet; this is a sequence of guided lessons** meant to be internalized, in order, with concepts that build cumulatively from the ground up. Once a card has been learned, it can be directly incorporated into **spaced-repetition learning software like [Anki](https://apps.ankiweb.net/)**, which leverages a scientifically-backed algorithm to ensure you remember what you learn, _efficiently_ and _permanently_. Because of the small chunks, you can also make significant progress with just a few minutes of effort per day. To provide practice applying the ideas as soon as they’re introduced, **hands-on projects** are integrated throughout, with solution code.\n\n## :world_map: Scope\nThe material focuses on the **_programmable geometry pipeline_**—creating form and color through code, logic, and mathematics. It covers the irreducible minimum required to build a 3D engine from scratch. While it establishes the **foundation for all graphics tasks**, it does not cover external asset management (like texture image loading), focusing instead on the state machine and the vertex/fragment logic essential for procedural graphics and tools like the [RMF Engine](https://github.com/GregStanton/proposal-rmf-engine) designed by this primer's author. It's **self contained**, with intuitive explanations of the mathematical prerequisites. Recommendations on leveraging the covered skills are provided at the end, including an annotated list of links to high-quality projects and advanced resources.\n\n# Background\nBefore diving into the programmable geometry pipeline, we'll make sure we know the lay of the land, and that we have the prerequisite concepts and skills in place.\n\n## :national_park: The landscape: Browser-based, hardware-accelerated graphics\nWhile this primer focuses on WebGL2 (a.k.a. WebGL 2.0) and GLSL, it's helpful to understand how these technologies fit within the broader landscape, which includes two related Web APIs, each capable of both 2D and 3D graphics. The computational demands of 3D graphics means that these APIs are designed to leverage GPUs, efficient hardware that's shipped in virtually all devices manufactured since the late 2000s (phones, tablets, laptops, desktops).\n\n* **WebGL and GLSL**\n  * **Current lingua franca** for hardware-accelerated graphics on the web\n  * **Wide employer demand**, indicating extensive current usage\n  * **Mature support in all major browsers** (since 2014 for 1.0, 2022 for 2.0), indicating a large ecosystem\n* **WebGPU and WGSL**\n  * **Emerging tech** meant as an _eventual_ WebGL replacement, for graphics, computation, and native-feeling apps (e.g., via Electron)\n  * **Nascent employer demand** focused on innovation and adaptation of WebGL code\n  * **Initial support in all major browsers** (as of mid-2025), with production deployments under development but impeded by significant inconsistencies, limitations, and bugs across browser implementations, operating systems, and hardware platforms\n\n**Common characteristics:**  \nBoth use the same graphics concepts, meaning that learning one makes it easier to learn the other. Both are significantly lower-level technologies relative to typical JavaScript development, as they offer direct interaction with the underlying GPU hardware.\n\n**Coexistence likely for 5–10 years or more:**  \nLibraries and applications with dual-backend architectures will likely be typical for at least five to ten years, and possibly longer, similar to the gradual rollout of WebGL and the coexistence of WebGL 1.0 and 2.0.\n\n**Updates to this section are welcome:**  \nAs the landscape evolves, pull requests that incorporate major updates to this background section will be welcome.\n\n## :closed_book: Prerequisite topics\nPrerequisites include both programming and math.\n\n**Programming:** \nKnowledge of HTML and JavaScript is assumed.\n\n**Mathematics:** \nSimple, concise explanations are provided for the topics below.\n\n* 3D primitives, including triangle strips and triangle fans\n* Matrix representations of geometric transformations\n* Homogeneous coordinates in projective geometry\n* Transforms in the standard 3D rendering pipeline\n\n## :open_book: Prerequisite explanations\n\nThis section explains the mathematical prerequisites at the level of detail we will need, with references for anyone desiring additional detail.\n\n### 3D primitives (drawing modes)\n\nThe image below is sufficient for understanding WebGL drawing modes (shape “kinds” in p5.js):\n\n\u003cimg \n  width=\"828\" \n  height=\"517\" \n  alt=\"A diagram illustrating the meaning of each drawing mode available in WebGL, including the following: `gl.POINTS`, `gl.LINES`, `gl.LINE_STRIP`, `gl.LINE_LOOP`, `gl.TRIANGLES`, `gl.TRIANGLE_STRIP`, `gl.TRIANGLE_FAN`.\"\n  src=\"https://github.com/user-attachments/assets/3cd05534-3f2a-412c-a10e-e29ef8e6bd52\" \n/\u003e\n\n*Attribution:* [“*Available WebGL shapes”*](https://miro.medium.com/v2/resize:fit:1100/format:webp/0*HQHB5lCGqlOUiysy.jpg) *appears in [A Brief Introduction to WebGL](https://medium.com/trabe/a-brief-introduction-to-webgl-5b584db3d6d6), by Martín Lamas.*\n\n### Matrix transformations and homogeneous coordinates\nBelow, we explain the two concepts from higher-level math that we'll need. Anyone who is unfamiliar with vectors, or who desires more detailed explanations of the two concepts explained here, may consult an [overview of the relevant math concepts](https://math.hws.edu/graphicsbook/c3/s5.html) in the online book _Introduction to Computer Graphics_, by David J. Eck.\n\n1. **Matrix representations:** Although we won't be multiplying matrices manually, it will still be helpful to have a procedural understanding of matrix multiplication, which is covered in this [ten-minute YouTube video](https://youtu.be/2spTnAiQg4M?si=Qz-DjwWKN3D9wzQR). It will also be helpful for you to know that matrix multiplication represents geometric transformations. For example, if you want to rotate the point $(1, 1)$ around the origin in the plane, you can accomplish this by multiplying a vector with components `[1, 1]` by a _rotation matrix_. It's not necessary to know how to define matrices for rotations or other transformations; it's enough to know that multiplying by a matrix accomplishes a transformation. Specific APIs for programming matrix operations are not assumed.\n\n2. **Homogeneous coordinates:** Homogeneous coordinates are to projective geometry what Cartesian coordinates are to Euclidean geometry. This is a very cool idea that allows us to represent not just _linear_ transformations (like scaling, rotating, shearing) via matrix multiplication, but also affine transformations (like translations), and even perspective projections (which make distant objects appear smaller). This is accomplished by including one extra coordinate, allowing us to represent both _points_ (which can be translated) and _directions_ (which cannot). It works as follows. When `w` is `0`, translation vectors are annihilated (multiplied by zero), so `[x, y, z, 0]` represents the direction `[x, y, z]`. When `w` is `1`, the translation vectors are preserved (multiplied by 1), so `[x, y, z, 1]` represents the point `[x, y, z]`. When `w` is a general nonzero value, the vector `[x, y, z, w]` represents the 3D point `[x / w, y / w, z / w]`.\n\n### Overview of coordinate systems\nIt’s enough to understand the significance of each source and target space, from local to screen space, and to know the sequence of transformations between them. The diagram below contains the essentials.\n\n\u003cimg \n  width=\"800\" \n  height=\"394\" \n  alt=\"A diagram showing the standard sequence of 3D graphics transforms, from local to world space (via the model matrix), from world to view space (via the view matrix), from view space to clip space (via the projection matrix), and from clip space to screen space (via the viewport transform).\"\n  src=\"https://github.com/user-attachments/assets/197931d8-81bc-4b73-ac91-34c7111fa18a\" \n/\u003e\n\n*Attribution:* [*coordinate_systems.png*](https://learnopengl.com/img/getting-started/coordinate_systems.png) *by [Joey de Vries](https://x.com/JoeyDeVriez) appears in [Coordinate Systems](https://learnopengl.com/Getting-started/Coordinate-Systems) and is licensed under [CC BY 4.0](http://creativecommons.org/licenses/by/4.0/)*.\n\nThe basic role of each space is indicated by the diagram. An example will clarify this further, so let's imagine we are drawing a model car in 3D.\n\n* **Local space**: It's easiest if we can design one tire, centered at the origin. This is _local space_.\n* **World space**: Then we move to the space where the car is, so we can attach the wheel in four places. This is _world space_.\n* **View space**: To view our car, we move into the viewer's space, with the viewer's eye (or camera) being the origin. This is _view space_.\n* **Clip space**: To show what the viewer sees, we need to clip the space, leaving only what's in front of them. This is _clip space_.\n* **Screen space**: Finally, we need to display what the viewer sees on an actual 2D screen (in a viewport). This is _screen space_.\n\nWhile this explanation is sufficient for our purposes, additional details may be found in [Projection and viewing](https://math.hws.edu/graphicsbook/c3/s3.html) in Eck, or [Coordinate Systems](https://learnopengl.com/Getting-started/Coordinate-Systems) in the online book _Learn OpenGL_, by [Joey de Vries](https://joeydevries.com/#home).\n\n### Normalized device coordinates\nWe'll be directly dealing with normalized device coordinates early on. WebGL automatically converts clip-space coordinates to normalized-device coordinates, prior to applying the viewport transform. By making coordinates range between -1 and 1, it becomes simple to stretch them to match the dimensions of the viewport.\n\n\u003cimg \n  width=\"503\" \n  height=\"440\" \n  alt=\"A cubic space, with a coordinate system whose origin is at the center of the cube. A horizontal axis points right, a vertical axis points up, and a depth axis points away. Values along each axis range between -1 and 1.\"\n  src=\"https://github.com/user-attachments/assets/ea261f7e-18ed-4141-81fd-3e6de54513ce\"\n/\u003e\n\n*Attribution:* *Image of NDC space (referred to as “clipspace” in original source) appears in [WebGL model view projection - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_model_view_projection) and is licensed under [CC BY SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en).*\n\n## :computer: Programming tips\n\nYou may find the following knowledge and experience helpful:\n\n* **The notion of a [statically typed language](https://developer.mozilla.org/en-US/docs/Glossary/Static_typing):** It's enough to know that in some languages, it's necessary to explicitly declare variable types\u0026mdash; like `bool` for a Boolean (true or false), or `int` for an integer ($\\ldots, -2, -1, 0, 1, 2, \\ldots$), or `float` for real numbers (decimal numbers). This may include syntax like `const int myInteger = 10;` instead of `const myInteger = 10;`\n* **Experience creating graphics with a high-level library like [p5.js](https://p5js.org/):** You can dive directly into WebGL2 \u0026 GLSL if you like to start with the nitty gritty. However, if you like to start by practicing the high-level concepts, such as making a 3D shape out of triangles without lots of low-level detail, then starting with a library like p5.js is a great option. In that case, this [introduction to coding with p5.js](https://www.youtube.com/playlist?list=PLRqwX-V7Uu6Zy51Q-x9tMWIv9cueOFTFA) from The Coding Train is an excellent choice.\n\n## :memo: Anki tip: Learning lists\nThe cards in these notes sometimes have a full list as an answer. Lists tend to be more cognitively demanding and can disrupt mental flow. To mitigate this effect, the list cards include hints to make them easier, but you can customize the approach to your own background using the following list-learning principles:\n\n* Create cards explaining how each list item connects conceptually to the next item (essentially creating a mental **[linked list](https://en.wikipedia.org/wiki/Linked_list)**, a form of **[elaborative encoding](https://en.wikipedia.org/wiki/Elaborative_encoding)** from cognitive science)\n* Include a hint explaining how to [**chunk**](https://en.wikipedia.org/wiki/Chunking_(psychology)) a longer list into only 3–4 items (chunks can be conceptual, or arbitrary, as with phone numbers)\n* Add a single **[acronym or a mnemonic phrase](https://en.wikipedia.org/wiki/Mnemonic)**, especially for ordered lists with seemingly arbitrary names (e.g., in biology, \"Do kings play chess on fine green silk?\" is a mnemonic for domain, kingdom, phylum, class, order, family, genus, species)\n* Implement lists using [**cloze deletion**](https://notes.andymatuschak.org/zPJt42JTcoAPTTTa2vdDonV), especially if the above techniques prove difficult, in software like Anki (e.g., create cards where all items are revealed except for one)\n\nHints should be included on the _back_ of a card (along with the answer), rather than the front. They serve as a reminder of how to internalize the idea, in case you fail to retrieve it from memory. If you rely on a hint on the front of a card, you may have trouble remembering it without that extra cue.\n\n# Introduction \u003ca title=\"™/®Khronos Group, Public domain, via Wikimedia Commons\" href=\"https://commons.wikimedia.org/wiki/File:WebGL_Logo.svg\"\u003e\u003cimg width=\"64\" alt=\"The Official WebGL Logo\" src=\"https://upload.wikimedia.org/wikipedia/commons/2/25/WebGL_Logo.svg\"\u003e\u003c/a\u003e \u003ca title=\"Jim McKeeth, CC BY-SA 4.0 \u0026lt;https://creativecommons.org/licenses/by-sa/4.0\u0026gt;, via Wikimedia Commons\" href=\"https://commons.wikimedia.org/wiki/File:GLSL_Logo_(Unofficial).svg\"\u003e\u003cimg width=\"48\" alt=\"OpenGL Shading Language logo (Unofficial)\" src=\"https://upload.wikimedia.org/wikipedia/commons/6/6a/GLSL_Logo_%28Unofficial%29.svg\"\u003e\u003c/a\u003e\n\nAs with all sections of this primer, the current introductory section is self contained. Since the concepts covered here are foundational, sources are provided. Anyone hungry for additional context on subsequent sections will be well served by the [MDN WebGL Reference](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API), the [OpenGL ES 3.0 Specification](https://registry.khronos.org/OpenGL/specs/es/3.0/es_spec_3.0.pdf), and [The OpenGL ES® Shading Language 3.00.6](https://registry.khronos.org/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf).\n\n*Image attributions: ™/®Khronos Group, Public domain; Jim McKeeth, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/); both via Wikimedia Commons*\n\n## Shader basics\nWe begin by defining basic terms, and the core software units that process our geometry.\n\n\u003cdetails\u003e\n\u003csummary\u003e\n  \u003cstrong\u003eQ:\u003c/strong\u003e \n  What are the geometric primitives in WebGL?\n\u003c/summary\u003e\n\u003cp\u003e\n  \u003cstrong\u003eA:\u003c/strong\u003e\n  Points, lines, and triangles. (Typically, it’s all triangles.)\n\u003c/p\u003e\n\u003cp\u003e\n  \u003cstrong\u003eSource:\u003c/strong\u003e \n  \u003ca href=\"https://webgl2fundamentals.org/webgl/lessons/webgl-fundamentals.html\"\u003eWebGL2 Fundamentals\u003c/a\u003e, \u003ca href=\"https://webgl2fundamentals.org/webgl/lessons/webgl-points-lines-triangles.html\"\u003eWebGL2 Points, Lines, and Triangles\u003c/a\u003e, \u003ca href=\"https://en.wikipedia.org/wiki/Geometric_primitive\"\u003eGeometric primitive - Wikipedia\u003c/a\u003e\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What mathematical concept unifies points (0D), lines (1D), and triangles (2D)?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Each of these is a \u003cem\u003esimplex\u003c/em\u003e, the simplest n-dimensional shape in its respective dimension.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNote:\u003c/strong\u003e This term is not commonly used in graphics, but it's fundamental in mathematics, which is excellent at unifying seemingly disparate ideas.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://en.wikipedia.org/wiki/Simplex\"\u003eSimplex - Wikipedia\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In computer graphics, what is a vertex?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e As in geometry, a vertex is one of a set of points that defines a shape (e.g. the three corners of a triangle). A vertex may have additional attributes for rendering (drawing), such as a color.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://en.wikipedia.org/wiki/Vertex_(computer_graphics)\"\u003eVertex (computer graphics) - Wikipedia\u003c/a\u003e, \u003ca href=\"https://en.wikipedia.org/wiki/Vertex_(geometry)\"\u003eVertex (geometry) - Wikipedia\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In computer graphics, what is a pixel?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It’s the smallest visual element on a screen. (It’s also known as a “picture element,” analogous to a chemical element in the periodic table). It’s usually a tiny square.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://en.wikipedia.org/wiki/Pixel\"\u003ePixel - Wikipedia\u003c/a\u003e, \u003ca href=\"https://en.wikipedia.org/wiki/Chemical_element\"\u003eChemical element - Wikipedia\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In computer graphics, what is a fragment?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It's a potential pixel. (For example, if part of a line is behind an opaque triangle, the obscured \u003cem\u003efragments\u003c/em\u003e of that line will be discarded, and won't end up coloring a pixel on the screen.) \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://en.wikipedia.org/wiki/Fragment_(computer_graphics)\"\u003eFragment (computer graphics) - Wikipedia\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What two pieces of code comprise a WebGL program? Name them.\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A \u003cem\u003evertex shader\u003c/em\u003e and a \u003cem\u003efragment shader\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://webgl2fundamentals.org/webgl/lessons/webgl-fundamentals.html\"\u003eWebGL2 Fundamentals\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What does a vertex shader do?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It computes a vertex position.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://webgl2fundamentals.org/webgl/lessons/webgl-fundamentals.html\"\u003eWebGL2 Fundamentals\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What does a fragment shader do?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It computes a fragment color.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://webgl2fundamentals.org/webgl/lessons/webgl-fundamentals.html\"\u003eWebGL2 Fundamentals\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Conceptually, the execution of a vertex or fragment shader behaves like what standard programming structure? (A loop, an object, or a function?)\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A function.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNote:\u003c/strong\u003e While WebGL wraps this code in a \u003cem\u003eshader object\u003c/em\u003e, the code itself defines a single function.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://webgl2fundamentals.org/webgl/lessons/webgl-fundamentals.html\"\u003eWebGL2 Fundamentals\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e If a shader only computes one vertex position or one fragment color, why does a WebGL program consist of only two shaders?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The vertex shader is executed for every single vertex, and the fragment shader is executed for every single fragment.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://webgl2fundamentals.org/webgl/lessons/webgl-shaders-and-glsl.html\"\u003eWebGL2 Fundamentals\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n## Software and hardware\nNow we zoom out, to understand the context in which our shaders are situated.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Is WebGL a language or an API?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It's an API. (It allows certain graphics features to be accessed through JavaScript.) \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://en.wikipedia.org/wiki/WebGL\"\u003eWebGL - Wikipedia\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What software design pattern best describes the behavior of WebGL?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A state machine. (You set a state, and it persists until changed.)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What is a state machine?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A mathematical model of computation defined by a list of states, initial values for those states, and the inputs that trigger each transition.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://en.wikipedia.org/wiki/Finite-state_machine\"\u003eFinite-state machine - Wikipedia\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL2, what language is used specifically to code vertex shaders and fragment shaders?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e GLSL (OpenGL Shading Language)\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNote:\u003c/strong\u003e More precisely, WebGL2 uses GLSL ES 3.00.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://webgl2fundamentals.org/webgl/lessons/webgl-fundamentals.html\"\u003eWebGL2 Fundamentals\u003c/a\u003e, \u003ca href=\"https://en.wikipedia.org/wiki/OpenGL_Shading_Language\"\u003eOpenGL Shading Language - Wikipedia\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In both WebGL and OpenGL, what does \"GL\" stand for?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Graphics Library\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://en.wikipedia.org/wiki/WebGL\"\u003eWebGL - Wikipedia\u003c/a\u003e, \u003ca href=\"https://en.wikipedia.org/wiki/OpenGL\"\u003eOpenGL - Wikipedia\u003c/a\u003e \u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Must variable and function declarations have a declared type in GLSL?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Yes.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://webgl2fundamentals.org/webgl/lessons/webgl-fundamentals.html\"\u003eWebGL2 Fundamentals\u003c/a\u003e, \u003ca href=\"https://en.wikipedia.org/wiki/Type_system\"\u003eType system - Wikipedia\u003c/a\u003e, \u003ca href=\"https://registry.khronos.org/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf\"\u003eThe OpenGL ES®\n Shading Language 3.00.6\u003c/a\u003e (page 22)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What general-purpose language is the syntax of GLSL patterned after?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e C\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://webgl2fundamentals.org/webgl/lessons/webgl-fundamentals.html\"\u003eWebGL2 Fundamentals\u003c/a\u003e, \u003ca href=\"https://en.wikipedia.org/wiki/OpenGL_Shading_Language#:~:text=OpenGL%20Shading%20Language%20\\(GLSL\\)%20is,on%20the%20C%20programming%20language\"\u003eOpenGL Shading Language - Wikipedia\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What hardware component does WebGL run on?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The GPU (graphics processing unit)\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource:\u003c/strong\u003e \u003ca href=\"https://webgl2fundamentals.org/webgl/lessons/webgl-fundamentals.html\"\u003eWebGL2 Fundamentals\u003c/a\u003e, \u003ca href=\"https://en.wikipedia.org/wiki/Graphics_processing_unit\"\u003eGraphics processing unit - Wikipedia\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What are \u003cem\u003ecores\u003c/em\u003e of a CPU or GPU? Answer with a simple analogy.\u003c/summary\u003e\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Cores are like independent brains.\u003c/p\u003e\u003c/details\u003e\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What's the main difference between the cores of CPUs (central processing units) and the cores of GPUs (graphics processing units)?\u003c/summary\u003e\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e CPUs have a few versatile cores, and GPUs have thousands of specialized cores.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e A CPU core is like a chef (few in number, versatile), whereas a GPU is like a line cook (great in number, specialized).\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What's the benefit of running shaders on GPUs?\u003c/summary\u003e\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A shader that computes a single position or color can be run for thousands of vertices or fragments in parallel.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e If you have ten chefs plating dishes vs. a thousand line cooks plating dishes, which will win a race to plate \u003cem\u003eone million\u003c/em\u003e dumplings?\u003c/p\u003e\u003c/details\u003e\n\n## Pipeline basics\nNow that we understand the basic idea of shaders, and key aspects of the software and hardware that power them, we consider how shader execution is organized.\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e The programmable geometry pipeline consists of which two interacting sequences?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The \u003cstrong\u003ecoordinate pipeline\u003c/strong\u003e (mathematical spaces) and the \u003cstrong\u003eexecution pipeline\u003c/strong\u003e (hardware stages).\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In 3D graphics, what is the standard sequence of \u003cem\u003espaces\u003c/em\u003e in the coordinate pipeline? List them in order.\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e\u003c/p\u003e \u003col\u003e \u003cli\u003e\u003cstrong\u003eLocal space\u003c/strong\u003e (coordinates relative to an object's origin) \u003c/li\u003e \u003cli\u003e\u003cstrong\u003eWorld space\u003c/strong\u003e (coordinates relative to the origin of the world in which objects are placed) \u003c/li\u003e \u003cli\u003e\u003cstrong\u003eView space\u003c/strong\u003e (coordinates relative to the camera/eye) \u003c/li\u003e \u003cli\u003e\u003cstrong\u003eClip space\u003c/strong\u003e (coordinates accounting for the eye's field of vision) \u003c/li\u003e \u003cli\u003e\u003cstrong\u003eScreen space\u003c/strong\u003e (coordinates for the physical viewport)\u003c/li\u003e\u003c/ol\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In 3D graphics, what is the standard sequence of \u003cem\u003etransforms\u003c/em\u003e in the coordinate pipeline? List them in order, with source and target spaces.\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e\u003c/p\u003e \u003col\u003e \u003cli\u003e\u003cstrong\u003eModel transform:\u003c/strong\u003e local $\\to$ world \u003c/li\u003e \u003cli\u003e\u003cstrong\u003eView transform:\u003c/strong\u003e world $\\to$ view \u003c/li\u003e \u003cli\u003e\u003cstrong\u003eProjection transform:\u003c/strong\u003e view $\\to$ clip \u003c/li\u003e \u003cli\u003e\u003cstrong\u003eViewport transform:\u003c/strong\u003e clip $\\to$ screen\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003eNote:\u003c/strong\u003e A technical distinction must be made regarding the viewport transform's source space. When we cover the details in separate cards, this will be explained.\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What is rasterization?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The process of converting vector geometry (points, lines, triangles) into fragments.\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what are the main stages of the \u003cem\u003eexecution\u003c/em\u003e pipeline? List them in order.\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eVertex shader\u003c/strong\u003e (positions the geometry) \u003cbr /\u003e \u003cstrong\u003e$\\to$ Rasterization\u003c/strong\u003e (converts vector geometry into fragments) \u003cbr /\u003e \u003cstrong\u003e$\\to$ Fragment shader\u003c/strong\u003e (computes the color of each fragment) \u003cbr /\u003e \u003cstrong\u003e$\\to$ Fragment processing\u003c/strong\u003e (determines how fragments translate into pixels)\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eNote:\u003c/strong\u003e When we cover the details, we'll reveal what's inside the \"black box\" between the vertex shader and rasterization (see the diagram below).\u003c/p\u003e \n\n```\nvertex shader  --\u003e  rasterization  --\u003e  fragment shader  --\u003e  fragment processing\n                ^\n          (\"black box\")\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Does the coordinate pipeline span the entire execution pipeline?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e No. The coordinate pipeline finishes just before rasterization begins.\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e The viewport transform at the end of the coordinate pipeline gets geometry into screen space; right after that, it's possible to identify fragments of primitives that cover particular pixels.\u003c/p\u003e \u003c/details\u003e\n\n## Access syntax\nNow we learn how to access the world of WebGL2 that we just described.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In the DOM, what HTML element provides the drawing surface for WebGL?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The \u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e element.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e How do we access the WebGL2 API?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003ecanvas.getContext('webgl2')\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What does \u003ccode\u003ecanvas.getContext('webgl2')\u003c/code\u003e return?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A \u003ccode\u003eWebGL2RenderingContext\u003c/code\u003e.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e A \u003ccode\u003eWebGL2RenderingContext\u003c/code\u003e is often given what abbreviated name in code?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What is the 2D version of \u003ccode\u003eWebGL2RenderingContext\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003eCanvasRenderingContext2D\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n# 🎨 Hello canvas\nIt’s time to make our first project! We just need to learn a few additional concepts.\n\n## Colors and buffers\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What color space is used by the WebGL context?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e RGBA (red, green, blue, alpha)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What is the valid range for color values in WebGL (red, green, blue, and alpha)?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003e0.0\u003c/code\u003e to \u003ccode\u003e1.0\u003c/code\u003e (floating point numbers).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In a WebGL RGBA color, what value of A (alpha) indicates full opacity?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003e1.0\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In a WebGL context, what function sets the canvas color? Include any parameters.\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.clearColor(r, g, b, a)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What does \u003ccode\u003egl.clearColor(r, g, b, a)\u003c/code\u003e do?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It sets the \"clear color\" state but does \u003cem\u003enot\u003c/em\u003e change the colors on the screen.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what basic function erases buffers and assigns them preset values? Include any parameters.\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.clear(mask)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What are the standard buffers that \u003ccode\u003egl.clear()\u003c/code\u003e can affect?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Color, Depth, Stencil\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e When calling \u003ccode\u003egl.clear()\u003c/code\u003e, what constant do we pass to clear the color buffer?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.COLOR_BUFFER_BIT\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e When calling \u003ccode\u003egl.clear()\u003c/code\u003e, what constant do we pass to clear the depth buffer?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.DEPTH_BUFFER_BIT\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Why does \u003ccode\u003egl.clear()\u003c/code\u003e accept a bitmask as its parameter?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e To allow multiple buffers to be cleared simultaneously via a bitwise OR operation. (This is an optimization that eliminates the need for multiple function calls.)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e To clear multiple buffers \u003ccode\u003ebuffer1\u003c/code\u003e and \u003ccode\u003ebuffer2\u003c/code\u003e simultaneously with \u003ccode\u003egl.clear()\u003c/code\u003e, what syntax is used?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Syntax: \u003ccode\u003egl.clear(buffer1 | buffer2)\u003c/code\u003e. This uses the bitwise OR operator: \u003ccode\u003e|\u003c/code\u003e (a single pipe character).\u003c/p\u003e\n\u003c/details\u003e\n\n## Project 1: Colored canvas\n\u003cimg width=\"250\" height=\"250\" alt=\"yellow canvas\" src=\"https://github.com/user-attachments/assets/0498abe0-4899-4204-9549-36e62a7644fa\" /\u003e\n\u003cp\u003e\n  \u003cstrong\u003eProblem:\u003c/strong\u003e\n  Set up an \u003ccode\u003eindex.html\u003c/code\u003e file and a JavaScript file. Make a canvas, get the WebGL context, and use it to set the canvas to a color of your choosing.\n\u003c/p\u003e\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eSolution:\u003c/strong\u003e\u003c/summary\u003e\n\n```html  \n\u003c!DOCTYPE html\u003e  \n\u003chtml lang=\"en\"\u003e  \n\u003chead\u003e  \n    \u003cmeta charset=\"UTF-8\"\u003e  \n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e  \n    \u003ctitle\u003eYellow canvas\u003c/title\u003e  \n\u003c/head\u003e\n\u003cbody\u003e  \n    \u003ccanvas id=\"yellow-canvas\" width=\"400\" height=\"400\"\u003e  \n      A canvas painted yellow.  \n    \u003c/canvas\u003e\n    \u003cscript src=\"yellow-canvas.js\"\u003e\u003c/script\u003e  \n\u003c/body\u003e  \n\u003c/html\u003e  \n```\n\n```javascript  \nconst canvas = document.getElementById('yellow-canvas');  \nconst gl = canvas.getContext('webgl2');  \nconst yellow = [243 / 255, 208 / 255, 62 / 255, 1];\n\ngl.clearColor(...yellow);  \ngl.clear(gl.COLOR_BUFFER_BIT);  \n```\n\u003c/details\u003e\n\n# 🔺Hello triangle\nNow we'll work toward getting a triangle on the screen. This will take some effort, since we're going to make sure we understand all the low-level boilerplate.\n\n## Starting the data bridge (getting CPU data onto the GPU)\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what does VBO stand for?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Vertex Buffer Object\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what is the general purpose of a VBO?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e To store data in the GPU's memory.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what sorts of data are commonly stored in a VBO?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Vertex attribute data like positions, normals, colors, and texture coordinates.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, data in a VBO is stored in what data format?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Binary\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what does VAO stand for?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Vertex Array Object\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what is the purpose of a VAO?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Recording how to read data from the VBOs.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what does the term \u003cem\u003ebinding\u003c/em\u003e mean?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Setting an object (e.g. a VBO) as the \"active\" value for a particular state in the WebGL state machine.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what is the order of operations for creating and configuring the VAO and VBO?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eCreate and Bind the VAO.\u003c/li\u003e\n\u003cli\u003eCreate and Bind the VBO.\u003c/li\u003e\n\u003cli\u003eUpload buffer data.\u003c/li\u003e\n\u003cli\u003eConfigure attributes (tell VAO how to read the VBO).\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e Since the WebGL context is a state machine, it needs a place to define state (VAO) \u003cem\u003ebefore\u003c/em\u003e it can organize the data values (VBO). Once these are in place, we need to upload data, then tell the VAO how to read it.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what syntax creates a Vertex Array Object?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.createVertexArray()\u003c/code\u003e (this function does not take parameters)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what syntax binds a VAO?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.bindVertexArray(vao)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what syntax creates a buffer (VBO)?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.createBuffer()\u003c/code\u003e (this function does not take parameters)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what syntax binds a buffer?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.bindBuffer(target, buffer)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What are the two most common targets for \u003ccode\u003egl.bindBuffer\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.ARRAY_BUFFER\u003c/code\u003e, \u003ccode\u003egl.ELEMENT_ARRAY_BUFFER\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What kind of data is usually bound to \u003ccode\u003egl.ARRAY_BUFFER\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Vertex attribute data (e.g. position, normal, color, texture data)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What kind of data is usually bound to \u003ccode\u003egl.ELEMENT_ARRAY_BUFFER\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Index data (indicating which vertices to connect)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Can you give a concrete example to indicate the purpose of \u003ccode\u003egl.ELEMENT_ARRAY_BUFFER\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Suppose you want to create a rectangle from four vertices. This needs to be created out of triangles, and there are two ways to triangulate a rectangle. The element array buffer can be used to specify the triangulation, by indicating which vertices should be connected.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What syntax sends data to the currently bound buffer?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.bufferData(target, data, usage)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.bufferData(target, data, usage)\u003c/code\u003e, the \u003ccode\u003edata\u003c/code\u003e argument usually has what type?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003eFloat32Array\u003c/code\u003e (a JavaScript \u003cem\u003etyped array\u003c/em\u003e)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.bufferData\u003c/code\u003e, if the geometry will not change after it is uploaded, what usage constant should be passed?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.STATIC_DRAW\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, an attribute will not be used unless you explicitly turn it on, using what function? Name the function (don’t specify any parameters).\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.enableVertexAttribArray()\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what function tells the VAO how to interpret the data in the currently bound VBO? Name the function (don’t specify any parameters).\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n## Coordinates expected by WebGL\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, vertex coordinates in a VBO are expected to be in what space?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Local space. (Also known as \u003cem\u003emodel space\u003c/em\u003e.)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, vertex coordinates output by a vertex shader are expected to be in what space?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Clip space.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In a WebGL vertex shader, if you define an attribute as a \u003ccode\u003evec4\u003c/code\u003e but only provide $(x, y)$ data from the buffer, what values are automatically assigned to $z$ and $w$?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003ez\u003c/code\u003e = 0.0, \u003ccode\u003ew\u003c/code\u003e = 1.0.\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e Recall that a w-coordinate of 1 makes the vertex a point, rather than a direction, i.e. it is affected by translations.\u003c/p\u003e\n\u003c/details\u003e\n\n## Fixed-function coordinate transforms\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e When referring to a graphics pipeline, what does the term “fixed function” mean?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It refers to operations in the pipeline that are not programmable by the user, as they are pre-programmed into the hardware (or driver).\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, vertex coordinates in clip space are automatically converted to what space, after the vertex shader runs?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e NDC space (normalized device coordinates).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what operation sends clip space to NDC space? Name it.\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Perspective division.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what operation sends clip space to NDC space? Specify the input and output.\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e $(x, y, z, w) \\mapsto (\\frac{x}{w}, \\frac{y}{w}, \\frac{z}{w})$\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what is the range of $x$, $y$, and $z$ in NDC space?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e -1.0 to 1.0.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL Normalized Device Coordinates (NDC), where is the origin $(0,0,0)$?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The center.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL Normalized Device Coordinates (NDC), in which direction do the $x$, $y$, and $z$ axes point?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Directions: $x$ points right, $y$ points up, and $z$ points away (directionally, into the screen).\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e The xy-plane follows mathematical conventions ($x$ points right and $y$ points up). However, it’s a left-handed system.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, the depth buffer typically contains values in what range?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003e0.0\u003c/code\u003e to \u003ccode\u003e1.0\u003c/code\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e These are non-negative, as we’d expect of depth values, since \"depth\" implies a distance measured in only one direction. The depth range may be customized, but this is rarely necessary.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, the values in the depth buffer are determined by what transformation? Name it.\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The viewport transform.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what are the source and target spaces of the viewport transform?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e NDC space $\\to$ screen space.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eNote:\u003c/strong\u003e The source space is sometimes identified informally as clip space, which is the last space the user deals with prior to application of the viewport transform. However, 4D clip space is converted automatically (during a fixed-function stage) to 3D NDC space before the viewport transform is applied.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In web graphics, what is the difference between a viewport and a canvas, if any?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The viewport is the rectangular portion of the canvas that is rendered to (e.g., if a canvas is too large to show, the viewport may be smaller and may have scroll bars).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Conceptually, what does the viewport transform do in WebGL?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It scales and translates NDC space to match the dimensions and position of the viewport, and it converts z-values from NDC space (in $[-1, 1]$) to depth values (in $[0, 1]$ by default).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What syntax explicitly configures the viewport transform?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.viewport(x, y, width, height)\u003c/code\u003e, where the \u003ccode\u003ex\u003c/code\u003e and \u003ccode\u003ey\u003c/code\u003e parameters are the lower-left corner of the viewport, and the other parameters are the viewport's dimensions.\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, the \u003ccode\u003ex\u003c/code\u003e and \u003ccode\u003ey\u003c/code\u003e parameters of \u003ccode\u003egl.viewport()\u003c/code\u003e are measured in pixels relative to which corner of the canvas?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The bottom-left corner.\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e This is the standard Cartesian origin, but it differs from the standard HTML coordinate system (which starts at the top-left).\u003c/p\u003e\u003c/details\u003e\n\n## Pipeline details\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what steps happen automatically in the execution pipeline, after the vertex shader and before perspective division? Name but do not describe them.\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e\u003c/p\u003e \u003col\u003e\u003cli\u003ePrimitive assembly\u003c/li\u003e\u003cli\u003e Clipping\u003c/li\u003e\u003c/ol\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In the WebGL execution pipeline, why might primitive assembly be necessary? Give a simple example. \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Two vertices may be interpreted as disconnected points or a single line segment.\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, why might primitives be assembled prior to clipping? Answer with a simple example. \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Imagine a paper triangle is pinned to a rectangular corkboard, and one of its vertices extends off the corkboard's edge. You clip the offending portion with scissors. This gives the triangle an extra edge and two new vertices. WebGL adds extra vertices like these automatically, but that requires it to know the clipped vertex was part of a triangle.\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, why might clipping occur prior to perspective division?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e There's no sense in performing calculations for vertices that won't make it into the final scene. (In addition to efficiency, there are more significant problems that need to be avoided. So other acceptable answers include a wrap-around effect, where dividing by a negative $w$ causes objects behind the camera to be positioned in front of it, and division by zero, which could happen for example if a vertex is located at the eye's/camera's position.)\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what steps happen between the vertex shader and rasterization? List them in order.\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e\u003c/p\u003e \u003col\u003e \u003cli\u003e \u003cstrong\u003ePrimitive assembly\u003c/strong\u003e (primitives must be assembled before they can be clipped)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eClipping\u003c/strong\u003e (clipping prior to perspective division eliminates unnecessary computation)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003ePerspective division\u003c/strong\u003e (this converts 4D coordinates to familiar 3D coordinates)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eViewport transform\u003c/strong\u003e (this maps 3D vector geometry to the screen so it can be rasterized, i.e. fragmented according to the pixels it covers)\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003eNote:\u003c/strong\u003e The full execution pipeline is visualized below. The stages from this card are shown in all capital letters.\u003c/p\u003e\n\n```\nvertex shader\n  --\u003e PRIMITIVE ASSEMBLY\n  --\u003e CLIPPING\n  --\u003e PERSPECTIVE DIVISION\n  --\u003e VIEWPORT TRANSFORM\n  --\u003e rasterization\n  --\u003e fragment shader\n  --\u003e fragment processing\n```\n\n\u003c/details\u003e\n\n## Project 2: Create and bind VBO and VAO, supply triangle data\n\nThis project is continued from [Project 1](#project-1-colored-canvas).\n\n\u003cp\u003e\n  \u003cstrong\u003eProblem:\u003c/strong\u003e\n  Extend your \u003ccode\u003eyellow-canvas.js\u003c/code\u003e program so that it defines a triangle as a flat array of three $(x, y)$ vertices. Create and bind a VAO and VBO, and upload the triangle data to the VBO. Assume the triangle data will not change after it’s uploaded. (We won't render the triangle yet. We'll do that in the next project.)\n\u003c/p\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eSolution:\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript  \n// CANVAS\nconst canvas = document.getElementById('yellow-canvas');\nconst gl = canvas.getContext('webgl2');\nconst yellow = [243 / 255, 208 / 255, 62 / 255, 1];\n\ngl.clearColor(...yellow);\ngl.clear(gl.COLOR_BUFFER_BIT);\n\n// TRIANGLE\nconst TAU = 2 * Math.PI;\nconst r = 2 / 3;\nconst t0 = TAU / 4;\nconst dt = TAU / 3;\n\nconst triangleVertices = new Float32Array([\n  r * Math.cos(t0), r * Math.sin(t0), \n  r * Math.cos(t0 + dt), r * Math.sin(t0 + dt), \n  r * Math.cos(t0 + 2 * dt), r * Math.sin(t0 + 2 * dt),\n]);\n\n// STATE MANAGEMENT: VAO AND VBO\nconst vao = gl.createVertexArray();\ngl.bindVertexArray(vao);\nconst vbo = gl.createBuffer();\ngl.bindBuffer(gl.ARRAY_BUFFER, vbo);\ngl.bufferData(gl.ARRAY_BUFFER, triangleVertices, gl.STATIC_DRAW);\n```\n\u003c/details\u003e\n\n## GLSL ES 3.00 syntax\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, what is the syntax to declare a floating-point variable named \u003ccode\u003ealpha\u003c/code\u003e and initialize it to 1.0?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003efloat alpha = 1.0;\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e It is very similar to C or Java. Semicolons are required.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, \u003ccode\u003evec2\u003c/code\u003e, \u003ccode\u003evec3\u003c/code\u003e, and \u003ccode\u003evec4\u003c/code\u003e refer to vectors whose components have what data type?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e float (floating point number)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, a type (such as \u003ccode\u003evec4\u003c/code\u003e) is also a ____________.\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e constructor\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, how can you create a \u003ccode\u003evec4\u003c/code\u003e with components $(0.1, 0.2, 0.3, 0.4)$?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003evec4(0.1, 0.2, 0.3, 0.4)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, if \u003ccode\u003epos\u003c/code\u003e is a variable of type \u003ccode\u003evec2\u003c/code\u003e, how do you create a \u003ccode\u003evec4\u003c/code\u003e using \u003ccode\u003epos\u003c/code\u003e for the first two components, \u003ccode\u003e0.0\u003c/code\u003e for \u003ccode\u003ez\u003c/code\u003e, and \u003ccode\u003e1.0\u003c/code\u003e for \u003ccode\u003ew\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003evec4(pos, 0.0, 1.0)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n## Attribute interpolation\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In mathematics, what is \u003cem\u003einterpolation\u003c/em\u003e?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Interpolation refers to determining an \u003cem\u003einter\u003c/em\u003emediate value between two given values (e.g. finding a position between points A and B that's 40% of the distance from A to B).\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What's an example of an attribute that needs to be interpolated between vertices?\u003c/summary\u003e\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A color. (Other typical examples are normal vectors or texture coordinates.) \u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Why might a color need to be interpolated between vertices?\u003c/summary\u003e\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e If two vertices each have their own color, then this color may need to be interpolated in order to associate a color with a fragment in between them.\u003c/p\u003e\u003c/details\u003e\n\n## Shader syntax\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In a WebGL2 shader source string, what must the very first line be?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003e#version 300 es\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e This refers to GLSL ES 3.00.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\n  \u003cstrong\u003eQ:\u003c/strong\u003e \n  In a WebGL2 shader, what is wrong with the following code?\n  \n  ```javascript\n  const shader = `\n  #version 300 es\n  // more code here...\n  `;\n```\n\n\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e There is a newline after the backtick, creating a blank line above the version specification. It should look like this instead:\u003c/p\u003e\n\n```javascript\nconst shader = `#version 300 es\n// more code here...\n`;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, which shader stage requires an explicit precision declaration?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The fragment shader.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e If vertices aren’t in the right place, things go wrong, so high precision is mandated for vertex shaders, but lower precision is allowed for fragment shaders, e.g. to avoid draining battery on older mobile devices.)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In a GLSL shader, what’s the syntax to declare that floats should have high precision?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003eprecision highp float;\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In a GLSL shader, where does the line of code go that sets the precision of floats?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The standard location is at the very top (underneath the line that specifies the GLSL version).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, a shader begins with the execution of what function? What’s the syntax for it?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003evoid main() {/* code goes here */}\u003c/code\u003e (as the syntax indicates, this function takes no parameters and returns no value)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, what’s the general syntactical term for the \u003ccode\u003ein\u003c/code\u003e and \u003ccode\u003eout\u003c/code\u003e keywords?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e They are \u003cem\u003estorage qualifiers\u003c/em\u003e.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What do \u003ccode\u003ein\u003c/code\u003e and \u003ccode\u003eout\u003c/code\u003e storage qualifiers indicate in a vertex shader?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003ein\u003c/code\u003e = vertex attribute. \u003ccode\u003eout\u003c/code\u003e = data to be interpolated (previously a \u003ccode\u003evarying\u003c/code\u003e).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What do \u003ccode\u003ein\u003c/code\u003e and \u003ccode\u003eout\u003c/code\u003e storage qualifiers indicate in a fragment shader?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003ein\u003c/code\u003e = interpolated data (previously a \u003ccode\u003evarying\u003c/code\u003e). \u003ccode\u003eout\u003c/code\u003e = final fragment color.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL ES 3.00, what is the syntax for setting up a “port” for a shader to receive data?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003elayout(location = 0) in \u0026lt;type\u0026gt; \u0026lt;variableName\u0026gt;\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL ES 3.00, what is the meaning of \u003ccode\u003elayout(location = 0)\u003c/code\u003e, in the line \u003ccode\u003elayout(location = 0) in \u0026lt;type\u0026gt; \u0026lt;variableName\u0026gt;\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e “Receive data at location 0.”\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL ES 3.00, what is the meaning of \u003ccode\u003e\u0026lt;variableName\u0026gt;\u003c/code\u003e, in the line \u003ccode\u003elayout(location = 0) in \u0026lt;type\u0026gt; \u0026lt;variableName\u0026gt;\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e This is the name of the variable that contains the data received at location 0.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL ES 3.00, where does the line \u003ccode\u003elayout(location = 0) in \u0026lt;type\u0026gt; \u0026lt;variableName\u0026gt;\u003c/code\u003e go inside a shader?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It goes in the global scope of the shader, before \u003ccode\u003emain()\u003c/code\u003e.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What special built-in variable must the vertex shader write to?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl_Position\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In a GLSL vertex shader, what is the data type of the built-in variable \u003ccode\u003egl_Position\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003evec4\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL ES 3.00, what is the syntax to define the output color variable in a fragment shader?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003eout vec4 fragColor;\u003c/code\u003e (You can name the variable whatever you want, but \u003ccode\u003efragColor\u003c/code\u003e is conventional.)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL ES 3.00, where does the code defining the output color variable in a fragment shader go?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It goes in the global scope of the shader, before \u003ccode\u003emain()\u003c/code\u003e.\u003c/p\u003e\n\u003c/details\u003e\n\n## Finishing the data bridge (enabling and configuring attributes)\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e An attribute will not be used unless it’s explicitly turned on using what syntax?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.enableVertexAttribArray(index)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.enableVertexAttribArray(index)\u003c/code\u003e, what does \u003ccode\u003eindex\u003c/code\u003e represent?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The \u003ccode\u003elocation\u003c/code\u003e of the attribute that will receive the data in the shader (set by \u003ccode\u003elayout(location = index)\u003c/code\u003e).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What’s the signature of \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e? (Parameter list and return value.)\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e\u003cbr /\u003e\n\u003ccode\u003egl.vertexAttribPointer(index, size, type, normalized, stride, offset)\u003c/code\u003e\u003cbr /\u003e\n\u003cem\u003eReturn value:\u003c/em\u003e None ( \u003ccode\u003eundefined\u003c/code\u003e).\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e Mentally chunk the parameters into three pairs—\u003ccode\u003eindex\u003c/code\u003e, \u003ccode\u003esize\u003c/code\u003e; \u003ccode\u003etype\u003c/code\u003e, \u003ccode\u003enormalized\u003c/code\u003e; \u003ccode\u003estride\u003c/code\u003e, \u003ccode\u003eoffset\u003c/code\u003e.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e, what does the \u003ccode\u003eindex\u003c/code\u003e parameter represent?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The \u003ccode\u003elocation\u003c/code\u003e of the attribute that will receive the data in the shader (set by \u003ccode\u003elayout(location = index)\u003c/code\u003e).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e, what does the \u003ccode\u003esize\u003c/code\u003e parameter represent?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The number of components per vertex (e.g., \u003ccode\u003e2\u003c/code\u003e for a \u003ccode\u003evec2\u003c/code\u003e, \u003ccode\u003e3\u003c/code\u003e for a \u003ccode\u003evec3\u003c/code\u003e).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e, what does the \u003ccode\u003etype\u003c/code\u003e parameter represent?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The data type of the array components.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e, the \u003ccode\u003etype\u003c/code\u003e parameter is typically set to what value?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.FLOAT\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e \n  What precise data type is indicated by \u003ccode\u003egl.FLOAT\u003c/code\u003e?\n\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \n  A 32-bit (IEEE) floating point number.\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\n  \u003cstrong\u003eQ:\u003c/strong\u003e\n  A \u003ccode\u003egl.FLOAT\u003c/code\u003e consists of how many \u003cem\u003ebytes\u003c/em\u003e?\n\u003c/summary\u003e\n\u003cp\u003e\n  \u003cstrong\u003eA:\u003c/strong\u003e \n  4 bytes\n\u003c/p\u003e\n\u003cp\u003e\n  \u003cstrong\u003eHint:\u003c/strong\u003e \n  A \u003ccode\u003egl.FLOAT\u003c/code\u003e is a 32-bit floating-point data type. A byte consists of 8 bits.\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e, what does the \u003ccode\u003enormalized\u003c/code\u003e parameter represent?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A boolean value indicating whether integer data should be normalized to $[-1, 1]$ or $[0, 1]$ when converted to a float (has no effect for floats, so it's typically set to \u003ccode\u003efalse\u003c/code\u003e in that case, as enabling normalization would have no effect).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e, what is a basic use case for the \u003ccode\u003enormalized\u003c/code\u003e parameter?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e If RGB values for a color are provided in the range $[0, 255]$ (with a \u003ccode\u003etype\u003c/code\u003e of \u003ccode\u003egl.UNSIGNED_BYTE\u003c/code\u003e), setting the \u003ccode\u003enormalized\u003c/code\u003e parameter to true will automatically convert that data to floats in the required $[0.0, 1.0]$ range for color data.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e, what does the \u003ccode\u003estride\u003c/code\u003e parameter represent?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Byte offset (distance in bytes) between the start of one vertex attribute and the next one of the same type. (Equivalently, the number of bytes used to store attributes corresponding to one vertex\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e Imagine attributes are stored like \u003ccode\u003ex0, y0, u0, v0, x1, y1, u1, v1…\u003c/code\u003e The stride tells WebGL that the memory occupied by \u003ccode\u003ex0, y0, u0, v0\u003c/code\u003e corresponds to one vertex.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What term do we use to describe attribute data like \u003ccode\u003ex0, y0, u0, v0, x1, y1, u1, v1…\u003c/code\u003e in which attributes of different kinds are stored together in the same buffer?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003cem\u003eInterleaved\u003c/em\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What term do we use to describe attribute data like \u003ccode\u003ex0, y0, x1, y1,…\u003c/code\u003e in which attributes in a buffer all have the same kind (e.g. they’re all positions)?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003cem\u003eTightly packed\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e If only positions are represented, then that means there’s zero space between positions (e.g. we don’t have position data, then color data, then position data, etc.).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What value do we give \u003ccode\u003estride\u003c/code\u003e when calling \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e, if we want data to be tightly packed?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003e0\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e This is a special case. If \u003ccode\u003e0\u003c/code\u003e were the byte offset from the start of one vertex position to the start of the next (for example), that’d mean there’s no position data. So WebGL interprets zero to mean “tightly packed,” (e.g., zero bytes between the \u003cem\u003eend\u003c/em\u003e of one vertex position and the \u003cem\u003estart\u003c/em\u003e of the next).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e If \u003ccode\u003estride\u003c/code\u003e is set to zero when calling \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e, how can WebGL determine the byte offset to get from one attribute to the next?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e WebGL interprets a \u003ccode\u003estride\u003c/code\u003e of \u003ccode\u003e0\u003c/code\u003e to mean the data is tightly packed (e.g. all position data, with no color data in between). It then automatically calculates the correct byte offset based on the \u003ccode\u003esize\u003c/code\u003e and \u003ccode\u003etype\u003c/code\u003e parameters.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e When calling \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e, suppose \u003ccode\u003esize\u003c/code\u003e is set to \u003ccode\u003e3\u003c/code\u003e, \u003ccode\u003etype\u003c/code\u003e is set to \u003ccode\u003egl.FLOAT\u003c/code\u003e, and \u003ccode\u003estride\u003c/code\u003e is set to zero. WebGL will automatically calculate that the byte offset between attributes is equal to what value?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A stride of zero means the data is tightly packed, so we have attributes with three components packed right next to each other. A \u003ccode\u003egl.FLOAT\u003c/code\u003e consists of four bytes. So, the byte offset is 3 components $\\times$ 4 bytes / component = 12 bytes.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Roughly, when might it be useful to use tightly packed attributes in a WebGL array buffer?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Using tightly packed attributes means that all positions would go into one array buffer, all colors would go into another, etc. This can be useful for \u003cstrong\u003edynamic geometry\u003c/strong\u003e, e.g. when positions need to be updated but not colors.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Roughly, when might it be useful to use interleaved attributes in a WebGL array buffer?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e This keeps all data for a single vertex close together in memory, which can be more efficient for \u003cstrong\u003estatic geometry\u003c/strong\u003e, e.g. where it’s not necessary to update positions but keep colors the same. (Interleaved attributes also make it possible to deal with just a single buffer.)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e, what does the \u003ccode\u003eoffset\u003c/code\u003e parameter represent?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The byte offset from the start of the buffer to the first component of the first vertex attribute.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e When \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e is called, how does WebGL know which VBO to read data from?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It uses whichever buffer is bound to the \u003ccode\u003egl.ARRAY_BUFFER\u003c/code\u003e when \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e is called.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What object stores the configuration set by \u003ccode\u003egl.vertexAttribPointer()\u003c/code\u003e and \u003ccode\u003egl.enableVertexAttribArray()\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The Vertex Array Object (VAO).\u003c/p\u003e\n\u003c/details\u003e\n\n## WebGL2 shader compilation\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cstrong\u003eQ:\u003c/strong\u003e \n    In WebGL, what are the high-level steps to setting up a shader object? Answer in words.\n  \u003c/summary\u003e\n\u003cp\u003e\n  \u003cstrong\u003eA:\u003c/strong\u003e\n    \u003col\u003e\n      \u003cli\u003e\u003cem\u003eCreate\u003c/em\u003e\u003c/li\u003e\n      \u003cli\u003e\u003cem\u003eUpload\u003c/em\u003e (the GLSL source code)\u003c/li\u003e\n      \u003cli\u003e\u003cem\u003eCompile\u003c/em\u003e\u003c/li\u003e\n      \u003cli\u003e\u003cem\u003eCheck\u003c/em\u003e (the compile status)\u003c/li\u003e\n      \u003cli\u003eIf compiling failed, \u003cem\u003eThrow\u003c/em\u003e the error and \u003cem\u003eDelete\u003c/em\u003e the shader.\u003c/li\u003e\n    \u003c/ol\u003e\n\u003c/p\u003e\n\u003cp\u003e\n  \u003cstrong\u003eHint:\u003c/strong\u003e\n  This list can be chunked into two stages. \n  \u003col\u003e\n    \u003cli\u003e \n      As with setting up a VBO, we need to \u003cem\u003eCreate\u003c/em\u003e the object before we \u003cem\u003eUpload\u003c/em\u003e to it.\n    \u003c/li\u003e\n    \u003cli\u003e\n      Since this is a program, we then need to \u003cem\u003eCompile\u003c/em\u003e it, \u003cem\u003eCheck\u003c/em\u003e for errors, and then \u003cem\u003eThrow\u003c/em\u003e errors and \u003cem\u003eDelete\u003c/em\u003e if needed.\n    \u003c/li\u003e\n  \u003c/ol\u003e\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what’s the syntax for creating a shader?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.createShader(type)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What are the two types of shaders passed to \u003ccode\u003egl.createShader()\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.VERTEX_SHADER\u003c/code\u003e and \u003ccode\u003egl.FRAGMENT_SHADER\u003c/code\u003e.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what’s the syntax to upload the GLSL source code string to a shader object?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.shaderSource(shader, sourceString)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what’s the syntax to compile a shader?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.compileShader(shader)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e After compiling a shader, what syntax checks if it succeeded?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.getShaderParameter(shader, gl.COMPILE_STATUS)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What is the return type of \u003ccode\u003egl.getShaderParameter(shader, gl.COMPILE_STATUS)\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003eBoolean\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e If \u003ccode\u003egl.getShaderParameter(shader, gl.COMPILE_STATUS)\u003c/code\u003e indicates an error has occurred, what syntax gets a string with information about the error?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Use \u003ccode\u003egl.getShaderInfoLog(shader)\u003c/code\u003e.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, why should you delete a shader object after it fails to compile?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e If it fails to compile, it’s garbage (useless). Deleting it prevents memory leaks (accumulation of useless memory).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What function removes a shader object from GPU memory?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.deleteShader(shader)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n## WebGL2 program linking\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what does it mean to “link” a program?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Linking a program connects it to dependencies, resulting in a program that’s executable.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Regarding executability, what is the difference between a shader object and a program object in WebGL?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A \u003cem\u003eshader\u003c/em\u003e is an intermediate (unlinked) compiled stage. A \u003cem\u003eprogram\u003c/em\u003e is linked and ready to run (like an \u003ccode\u003e.exe\u003c/code\u003e).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what are the high-level steps to setting up a program object? Answer in words.\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cem\u003eCreate\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eAttach\u003c/em\u003e (shaders)\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eLink\u003c/em\u003e (program)\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eCheck\u003c/em\u003e (the link status)\u003c/li\u003e\n\u003cli\u003eIf linking failed, \u003cem\u003eThrow\u003c/em\u003e (error) and \u003cem\u003eDelete\u003c/em\u003e (the program).\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what’s the syntax for creating a program object?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.createProgram()\u003c/code\u003e (no parameters)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what’s the syntax for attaching a shader to a program object?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.attachShader(program, shader)\u003c/code\u003e (attaches a vertex or a fragment shader)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e After attaching shaders to a program, what syntax connects them into a usable executable?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.linkProgram(program)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e After linking a WebGL program, how do you check if it succeeded?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.getProgramParameter(program, gl.LINK_STATUS)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What is the return type of \u003ccode\u003egl.getProgramParameter(program, gl.LINK_STATUS)\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003eBoolean\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e If \u003ccode\u003egl.getProgramParameter(program, gl.LINK_STATUS)\u003c/code\u003e indicates an error has occurred, what syntax gets a string with information about the error?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.getProgramInfoLog(program)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, why should you delete a program object after it fails to link?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e If it fails to link, it’s garbage (useless). Deleting it prevents memory leaks (accumulation of useless memory).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What function removes a program object from GPU memory?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.deleteProgram(program)\u003c/code\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n## Drawing\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL2, which function actually triggers the execution pipeline to run? Give two possible answers.\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.drawArrays()\u003c/code\u003e or \u003ccode\u003egl.drawElements()\u003c/code\u003e.\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e Prior to calling one of these functions, you are just setting up state. These commands tell the GPU to actually process the data through the shaders. They're your \"go\" buttons.\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In the WebGL2 API, what's the signature of \u003ccode\u003egl.drawArrays()\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.drawArrays(mode, first, count)\u003c/code\u003e\u003cbr /\u003e\n\u003cem\u003eReturn value:\u003c/em\u003e None ( \u003ccode\u003eundefined\u003c/code\u003e).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In the WebGL2 API, what does \"arrays\" refer to in \u003ccode\u003egl.drawArrays()\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e As it carries out the drawing task, this function aggregates vertex attributes from multiple arrays (e.g. position, color, and texture arrays), assembling all data for vertex 1, then for vertex 2, and so on.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.drawArrays(mode, first, count)\u003c/code\u003e, what are the possible values of the \u003ccode\u003emode\u003c/code\u003e parameter? Answer with conceptual descriptions.\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Disconnected points; disconnected lines, an open polyline, or a closed polyline; disconnected triangles, a triangle strip, or a triangle fan.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e The \u003ccode\u003emode\u003c/code\u003e parameter is analogous to the \u003ccode\u003ekind\u003c/code\u003e parameter in p5's \u003ccode\u003ebeginShape(kind)\u003c/code\u003e.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.drawArrays(mode, first, count)\u003c/code\u003e, what are the possible values of the \u003ccode\u003emode\u003c/code\u003e parameter? Answer with variable names.\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.POINTS\u003c/code\u003e; \u003ccode\u003egl.LINES\u003c/code\u003e, \u003ccode\u003egl.LINE_STRIP\u003c/code\u003e, \u003ccode\u003egl.LINE_LOOP\u003c/code\u003e; \u003ccode\u003egl.TRIANGLES\u003c/code\u003e, \u003ccode\u003egl.TRIANGLE_STRIP\u003c/code\u003e, \u003ccode\u003egl.TRIANGLE_FAN\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e The \u003ccode\u003emode\u003c/code\u003e parameter is analogous to the \u003ccode\u003ekind\u003c/code\u003e parameter in p5's \u003ccode\u003ebeginShape(kind)\u003c/code\u003e.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.drawArrays(mode, first, count)\u003c/code\u003e, what does the \u003ccode\u003efirst\u003c/code\u003e parameter represent?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The starting index to read from, in the arrays of vertex attributes. (Usually 0.)\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.drawArrays(mode, first, count)\u003c/code\u003e, what does the \u003ccode\u003ecount\u003c/code\u003e parameter represent?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The number of vertices to be processed (rendered).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e If you call \u003ccode\u003egl.drawArrays(mode, 0, 36)\u003c/code\u003e, how many times will the vertex shader execute?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e 36 times.\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e The vertex shader runs once for every vertex specified in the \u003ccode\u003ecount\u003c/code\u003e parameter.\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Before issuing a \u003ccode\u003egl.drawArrays\u003c/code\u003e command, what must you tell the GPU, conceptually?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e You must tell it which shader program to use.\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What syntax tells \u003ccode\u003egl.drawArrays\u003c/code\u003e which shader program to execute?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.useProgram(program)\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e This tells the WebGL state machine: \"For all subsequent draw calls, use this specific compiled executable.\"\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What's the main technical difference between \u003ccode\u003egl.drawArrays()\u003c/code\u003e and \u003ccode\u003egl.drawElements()\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.drawArrays()\u003c/code\u003e uses array buffers (bound to \u003ccode\u003egl.ARRAY_BUFFER\u003c/code\u003e) and \u003ccode\u003egl.drawElements()\u003c/code\u003e uses \u003cem\u003eelement\u003c/em\u003e array buffers (bound to \u003ccode\u003egl.ELEMENT_ARRAY_BUFFER\u003c/code\u003e).\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What's a guideline for deciding between using \u003ccode\u003egl.drawArrays()\u003c/code\u003e and \u003ccode\u003egl.drawElements()\u003c/code\u003e?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Use \u003ccode\u003egl.drawArrays()\u003c/code\u003e when there is little to no vertex sharing between primitives (e.g. six vertices for two triangles, each with its own vertices), and use \u003ccode\u003egl.drawElements()\u003c/code\u003e otherwise (e.g. four vertices for two triangles that share a side).\u003c/p\u003e\n\u003c/details\u003e\n\n## Project 3: Make boilerplate helper and draw triangle\n\u003cimg \n  width=\"250\" \n  height=\"250\" \n  alt=\"yellow canvas with an orange triangle in the center\" \n  src=\"https://github.com/user-attachments/assets/47448258-5800-45aa-8e61-a172ed90d46a\" \n/\u003e\n\n\u003cp\u003e\n\u003cstrong\u003eGoal:\u003c/strong\u003e Update \u003ccode\u003eyellow-canvas.js\u003c/code\u003e to render your existing triangle geometry in orange, on top of the yellow background.\n\u003c/p\u003e\n\n\u003cp\u003e\n\u003cstrong\u003eContext:\u003c/strong\u003e From \u003ca href=\"#project-2-create-and-bind-vbo-and-vao-supply-triangle-data\"\u003eProject 2\u003c/a\u003e, you already have the geometry (a \u003ccode\u003eFloat32Array\u003c/code\u003e of 2D coordinates) in a VBO, and a VAO that is currently bound. Now you need to build the program to process that data.\n\u003c/p\u003e\n\n\u003cstrong\u003eProject Specifications:\u003c/strong\u003e\n\n1.  \u003cstrong\u003eHelper Function:\u003c/strong\u003e Create a function \u003ccode\u003ecreateProgram(gl, vsSource, fsSource)\u003c/code\u003e at the bottom of your file.\n    * It must create two shaders and one program.\n    * It must compile the shaders and check their compile status.\n    * It must link the program and check its link status.\n    * \u003cstrong\u003eConstraint:\u003c/strong\u003e If any check fails, \u003cstrong\u003ethrow\u003c/strong\u003e an error and \u003cstrong\u003edelete\u003c/strong\u003e the faulty object to avoid memory leaks. Otherwise, return the \u003ccode\u003eprogram\u003c/code\u003e.\n2.  \u003cstrong\u003eShader Source Code:\u003c/strong\u003e Define two template strings, \u003ccode\u003evsSource\u003c/code\u003e and \u003ccode\u003efsSource\u003c/code\u003e.\n    * \u003cstrong\u003eVertex Shader:\u003c/strong\u003e\n        * Accept an attribute \u003ccode\u003eposition\u003c/code\u003e at location 0. Note that your buffer has 2 numbers per vertex, so this should be a \u003ccode\u003evec2\u003c/code\u003e.\n        * Output a \u003ccode\u003egl_Position\u003c/code\u003e. (Hint: You will need to convert your \u003ccode\u003evec2\u003c/code\u003e input.)\n    * \u003cstrong\u003eFragment Shader:\u003c/strong\u003e\n        * Declare the variable to output.\n        * Output the color orange: \u003ccode\u003evec4(1.0, 0.4, 0.0, 1.0)\u003c/code\u003e.\n3.  \u003cstrong\u003eExecution:\u003c/strong\u003e\n    * Call your helper to create the program.\n    * Tell WebGL to use this program.\n    * Draw the triangle.\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eSolution:\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\n// CANVAS\nconst canvas = document.getElementById('yellow-canvas');\nconst gl = canvas.getContext('webgl2');\nconst yellow = [243 / 255, 208 / 255, 62 / 255, 1];\n\ngl.clearColor(...yellow);\ngl.clear(gl.COLOR_BUFFER_BIT);\n\n// TRIANGLE\nconst TAU = 2 * Math.PI;\nconst r = 2 / 3;\nconst t0 = TAU / 4;\nconst dt = TAU / 3;\n\nconst triangleVertices = new Float32Array([\n  r * Math.cos(t0), r * Math.sin(t0), \n  r * Math.cos(t0 + dt), r * Math.sin(t0 + dt), \n  r * Math.cos(t0 + 2 * dt), r * Math.sin(t0 + 2 * dt),\n]);\n\n// SHADER SOURCE\nconst vsSource = `#version 300 es\nlayout(location = 0) in vec2 position;\n\nvoid main() {\n  gl_Position = vec4(position, 0.0, 1.0);\n}\n`;\n\nconst fsSource = `#version 300 es\nprecision highp float;\nout vec4 fragColor;\n\nvoid main() {\n  fragColor = vec4(1.0, 0.4, 0.0, 1.0);\n}\n`;\n\n// STATE MANAGEMENT: VAO AND VBO\nconst vao = gl.createVertexArray();\ngl.bindVertexArray(vao);\nconst vbo = gl.createBuffer();\ngl.bindBuffer(gl.ARRAY_BUFFER, vbo);\ngl.bufferData(gl.ARRAY_BUFFER, triangleVertices, gl.STATIC_DRAW);\ngl.enableVertexAttribArray(0);\ngl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n\n// CREATE AND USE PROGRAM TO DRAW\nconst program = createProgram(gl, vsSource, fsSource);\ngl.useProgram(program);\ngl.drawArrays(gl.TRIANGLES, 0, 3);\n\n// CREATION UTILITIES: SHADERS AND PROGRAM \nfunction createShader(gl, type, source) {\n  const shader = gl.createShader(type);\n  gl.shaderSource(shader, source);\n  gl.compileShader(shader);\n  \n  // Check success\n  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n    const shaderInfoLog = gl.getShaderInfoLog(shader);\n    gl.deleteShader(shader);\n    throw new Error(`Could not compile shader: ${shaderInfoLog}`);\n  }\n  return shader;\n}\n\nfunction createProgram(gl, vsSource, fsSource) {\n  const vs = createShader(gl, gl.VERTEX_SHADER, vsSource);\n  const fs = createShader(gl, gl.FRAGMENT_SHADER, fsSource);\n  \n  const program = gl.createProgram();\n  gl.attachShader(program, vs);\n  gl.attachShader(program, fs);\n  gl.linkProgram(program);\n  \n  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n    const programInfoLog = gl.getProgramInfoLog(program);\n    gl.deleteProgram(program);\n    throw new Error(`Could not link program: ${programInfoLog}`);\n  }\n  return program;\n}\n```\n\u003c/details\u003e\n\n# 🧊 Hello spinning cube\nTime for some 3D action!\n\n## Uniforms and matrices in GLSL\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, what storage qualifier is used for variables that remain constant for all vertices in a single draw call (e.g., a transformation matrix)?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003euniform\u003c/code\u003e\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, before you can set the value of a uniform, you must look up its address using what syntax?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.getUniformLocation(program, name)\u003c/code\u003e\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e Just as attributes have integer locations, uniforms have location objects.\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In \u003ccode\u003egl.getUniformLocation(program, name)\u003c/code\u003e, you must be sure that \u003ccode\u003ename\u003c/code\u003e has what data type?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A string. (Be sure to wrap the name of the uniform in single quotes, so that it's just a variable \u003cem\u003ename\u003c/em\u003e, not an actual variable.)\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What do \"row-major\" and \"column-major\" mean when specifying matrices?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Imagine reading a matrix aloud to someone else. You'll either read it to them row by row (\u003cem\u003erow-major\u003c/em\u003e order) or column by column (\u003cem\u003ecolumn-major\u003c/em\u003e order). (The same concept applies when storing a matrix in a flat array.)\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, what data type represents a $4\\times4$ matrix?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003emat4\u003c/code\u003e (a common shorthand for \u003ccode\u003emat4x4\u003c/code\u003e)\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL and GLSL, what is the convention regarding matrix order (column-major or row-major), if any? \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Always column major.\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e This is consistent with mathematical conventions, whereby the matrix of a transformation is built from vectors that are represented as columns.\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What is the order of multiplication when multiplying a matrix $M$ by a vector $v$, when following a column-major convention? \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e $Mv$ \u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e Since $v$ is a column, it must go on the right for the matrix product to be defined, in general.\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What is the order of multiplication when multiplying a matrix $M$ by a vector $v$, when following a row-major convention? \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e $vM$ \u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e Since $v$ is a row, it must go on the left for the matrix product to be defined, in general.\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, if you want to set the value of a uniform variable declared as a \u003ccode\u003emat4\u003c/code\u003e in GLSL, what syntax do you use?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.uniformMatrix4fv(location, transpose, data)\u003c/code\u003e\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e It stands for \"uniform Matrix 4 float vector,\" where \"float vector\" refers to the type of \u003ccode\u003edata\u003c/code\u003e used to specify the matrix.\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e When calling \u003ccode\u003egl.uniformMatrix4fv()\u003c/code\u003e in WebGL, what must the \u003ccode\u003etranspose\u003c/code\u003e argument always be?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003efalse\u003c/code\u003e\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e The \u003ccode\u003etranspose\u003c/code\u003e parameter is kept for consistency with OpenGL, but WebGL requires this to be \u003ccode\u003efalse\u003c/code\u003e, so that matrices are always in column-major order.\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e When calling \u003ccode\u003egl.uniformMatrix4fv()\u003c/code\u003e in WebGL, how is the \u003ccode\u003edata\u003c/code\u003e parameter typically specified?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It's typically specified as a \u003ccode\u003eFloat32Array\u003c/code\u003e (it could also be a sequence of separate 32-bit floats).\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What function must you call before setting any uniforms? \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.useProgram()\u003c/code\u003e\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Why must a program be in use before setting any uniforms? \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Uniforms are global to the \u003cem\u003eprogram object\u003c/em\u003e and are stored in that object, not in the global WebGL state. (WebGL needs to know \u003cem\u003ewhich\u003c/em\u003e program's memory you intend to update.)\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e WebGL clip space is left handed ($+z$ into screen). However, the popular \u003ccode\u003eglMatrix\u003c/code\u003e matrix library uses a right-handed system ($+z$ towards viewer), which aligns with standard mathematical conventions. Which matrix in \u003ccode\u003eglMatrix\u003c/code\u003e handles the conversion between them?\u003c/summary\u003e\n\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The projection matrix (it flips the $z$-axis).\u003c/p\u003e\n\u003c/details\u003e\n\n## GLSL matrix multiplication\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, how do we compute the matrix-vector product $Mv$, where $M$ is a \u003ccode\u003emat4\u003c/code\u003e and $v$ is a \u003ccode\u003evec4\u003c/code\u003e?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003eM * v\u003c/code\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, how do we compute the matrix product $AB$, where $A$ is a \u003ccode\u003emat4\u003c/code\u003e and $B$ is a \u003ccode\u003emat4\u003c/code\u003e? (Here, $AB$ refers to the standard matrix product, not an entrywise/Hadamard product.) \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003eA * B\u003c/code\u003e\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In GLSL, what happens if you try to multiply \u003ccode\u003evector * matrix\u003c/code\u003e (vector on the left)?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It treats the vector as a row vector.\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e This is valid syntax but usually not what we want, since WebGL adheres to column-major order.\u003c/p\u003e \u003c/details\u003e\n\n## 3D-state management (depth and culling)\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, what feature must be enabled to prevent background triangles from drawing on top of foreground triangles? Answer in words. \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The \u003cem\u003edepth test\u003c/em\u003e.\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What syntax enables the depth test in WebGL?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.enable(gl.DEPTH_TEST)\u003c/code\u003e\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Does setting \u003ccode\u003egl.enable(gl.DEPTH_TEST)\u003c/code\u003e require an active program?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e No.\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e Depth testing is part of the \u003cem\u003eglobal context state\u003c/em\u003e, not the program state.\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e When the depth test is enabled in WebGL, what update must you be sure to make every frame? Answer in words. \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Clear the depth buffer. (This ensures that old data doesn't persist.)\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In computer graphics, what is \"face culling\"?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It's an optimization that avoids drawing faces that wouldn't be visible anyway (e.g. the back face of a cube).\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, face culling is applied to triangles if they have what spatial relation to the camera?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e The triangles are culled if they are facing away from the camera.\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e Imagine that you color a paper triangle red, but if someone flips it over, they'll see it's still white on the other side. That's the back face. WebGL also has a way of determining which face of a triangle is the front and which is the back.\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e By default, WebGL determines a triangle is \"front-facing\" if its vertices are defined in what winding order?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Counter-Clockwise (CCW).\u003c/p\u003e \u003cp\u003e\u003cstrong\u003eHint:\u003c/strong\u003e This is the positive orientation in the xy-plane (starting from the positive x-axis, this direction moves us through Quadrant I first).\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What syntax enables face culling in WebGL?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003egl.enable(gl.CULL_FACE)\u003c/code\u003e\u003c/p\u003e \u003c/details\u003e\n\n## 3D geometry definition (winding order)\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, when defining the vertices of a 3D mesh (like a cube), in what winding order should you list the vertices for every face?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Counter-Clockwise (CCW).\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In WebGL, when determining the CCW winding order for a specific face of a 3D object, where should you imagine yourself standing?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Outside the object, looking directly at the face.\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e How does WebGL know when a face of a 3D object is hidden from view and can therefore be culled? \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e WebGL calculates the winding order on the screen; it assumes you defined all front faces with a CCW order, so if it sees a face with a CW order, it culls it (as it must be looking at the back).\u003c/p\u003e \u003c/details\u003e\n\n## The animation loop\nHere, we learn a general Web API for animations that is exposed to JavaScript. It can be used for many things. We will use it to create an animation with WebGL2.\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In the browser, what API is the standard for creating smooth animations? Answer with the precise syntax.\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003erequestAnimationFrame(callback)\u003c/code\u003e\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Why is \u003ccode\u003erequestAnimationFrame()\u003c/code\u003e so named? \u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It requests the browser to call the provided callback function, which determines the next frame in the animation.\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e How does \u003ccode\u003erequestAnimationFrame()\u003c/code\u003e behave when the browser tab is inactive (not visible)?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It pauses (or slows down significantly) to save battery and CPU cycles.\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e \u003ccode\u003erequestAnimationFrame()\u003c/code\u003e runs its callback exactly once. How do you create a continuous loop?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Call \u003ccode\u003erequestAnimationFrame\u003c/code\u003e recursively inside the callback function.\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What argument does \u003ccode\u003erequestAnimationFrame()\u003c/code\u003e automatically pass to its callback function?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e A \u003ccode\u003etimestamp\u003c/code\u003e argument (a \u003ccode\u003eDOMHighResTimeStamp\u003c/code\u003e type, indicating when the frame starts).\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \n  \u003csummary\u003e\n    \u003cstrong\u003eQ:\u003c/strong\u003e \n    What is the minimal code structure for a continuous animation loop created with \u003ccode\u003erequestAnimationFrame()\u003c/code\u003e? (Assume the callback is named \u003ccode\u003edraw\u003c/code\u003e).\n  \u003c/summary\u003e \n  \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e\u003c/p\u003e\n\n  ```javascript\n  function draw(timestamp) {\n    // 1. Update state and render...\n    // 2. Schedule next frame\n    requestAnimationFrame(draw);\n  }\n\n  // 3. Start the loop\n  requestAnimationFrame(draw);\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e The \u003ccode\u003etimestamp\u003c/code\u003e passed to the \u003ccode\u003erequestAnimationFrame()\u003c/code\u003e callback represents time in what unit?\u003c/summary\u003e\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Milliseconds.\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e The \u003ccode\u003etimestamp\u003c/code\u003e passed to the \u003ccode\u003erequestAnimationFrame()\u003c/code\u003e callback measures time elapsed since what event? (Be general).\u003c/summary\u003e\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e Since the time origin (usually when the page loaded).\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e In the context of an animation created with \u003ccode\u003erequestAnimationFrame()\u003c/code\u003e, what does it mean to calculate a \u003cem\u003ezeroed\u003c/em\u003e time?\u003c/summary\u003e\u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It refers to calculating an elapsed time starting when the animation logic begins, rather than when the page loaded.\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cstrong\u003eQ:\u003c/strong\u003e \n    What's a simple way to calculate a zeroed time for an animation made with \u003ccode\u003erequestAnimationFrame(callback)\u003c/code\u003e? Sketch your answer in code, using a callback function named \u003ccode\u003edraw\u003c/code\u003e.\n  \u003c/summary\u003e\n  \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e\u003c/p\u003e\n\n```javaScript\nlet startTime;\n\nfunction draw(timestamp) {\n  if (!startTime) {\n    startTime = timestamp;\n  }\n  const elapsed = timestamp - startTime;\n  \n  // draw logic...\n  \n  requestAnimationFrame(draw);\n}\n```\n  \n\u003c/details\u003e\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e What syntax stops a scheduled animation frame request made with \u003ccode\u003erequestAnimationFrame()\u003c/code\u003e?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e \u003ccode\u003ecancelAnimationFrame(requestID)\u003c/code\u003e\u003c/p\u003e \u003c/details\u003e\n\n\u003cdetails\u003e \u003csummary\u003e\u003cstrong\u003eQ:\u003c/strong\u003e Where do you get the \u003ccode\u003erequestID\u003c/code\u003e needed to cancel an animation frame request made with \u003ccode\u003erequestAnimationFrame()\u003c/code\u003e?\u003c/summary\u003e \u003cp\u003e\u003cstrong\u003eA:\u003c/strong\u003e It is the return value of the \u003ccode\u003erequestAnimationFrame()\u003c/code\u003e call.\u003c/p\u003e \u003c/details\u003e\n\n## Project 4: The Spinning Cube\n\n\u003cimg width=\"250\" height=\"250\" alt=\"spinning multicolored cube\" src=\"https://github.com/user-attachments/assets/57bca82d-cfbf-48d0-9623-bc764039f39b\" /\u003e\n\n**Goal:** Render a multicolored unit cube, centered at the origin, that rotates in 3D space. You may reuse logic from Project 3 as appropriate.\n\n**Allowed linear-algebra dependency:** You may use [glMatrix](https://glmatrix.net/) for the matrix transformations, by downloading [`gl-matrix-min.js`](https://github.com/toji/gl-matrix/blob/master/dist/gl-matrix-min.js) from the GitHub repo, putting it into a folder called `libs` in your project directory, and then including it in `index.html` with a `\u003cscript\u003e` element above the line where you include your own script. You may also use the [`glMatrix` documentation](https://glmatrix.net/docs/module-glMatrix.html) as a reference if needed. Note that the library exposes a global `glMatrix` object: you'll typically access functions via `glMatrix.mat4.create()`, `glMatrix.vec3.fromValues()`, etc. Also note that vectors and matrices (e.g. `mat4` and `vec3`) are all `Float32Array` instances.\n\n**Approach:** To allow distinct colors for each face, you may duplicate vertices. There will then be 36 vertices total: 6 faces $\\times$ 2 triangles $\\times$ 3 vertices.\n\n**Specifications:**\n\n1. **State Management:**\n   * Enable the depth test and face culling.\n   * Create a VAO.\n   * Create two VBOs: one for `positions`, one for `colors` (Note: You can use two \u003ccode\u003ebufferData\u003c/code\u003e calls and two \u003ccode\u003evertexAttribPointer\u003c/code\u003e calls attached to the same VAO).\n   * Configure `position` (attribute location 0) and `color` (attribute location 1).\n2. **Shaders:**\n   * **Vertex Shader:**\n     * Attributes: `in vec3 position`, `in vec3 color`.\n     * Uniforms: `uniform mat4 uModel`, `uniform mat4 uView`, `uniform mat4 uProjection`.\n     * Output: `out vec3 vColor` (\"v\" is conventional and stands for \"varying,\" just as \"u\" stands for \"uniform\" in `uModel`).\n     * Main: Set `gl_Position = uProjection * uView * uModel * vec4(position, 1.0);`. Pass `color` to `vColor`.\n   * **Fragment Shader:**\n     * Input: `in vec3 vColor`.\n     * Output: `fragColor` using the interpolated input color (alpha 1.0).\n3. **Matrix Logic (`glMatrix`):** Create model, view, and projection matrices. Upload view and projection matrices via `gl.uniformMatrix4fv`.\n    * **Model:** Use `mat4.create()`.\n    * **View:** Use `mat4.lookAt`. (Eye: `[0, 0, 4]`, Center: `[0, 0, 0]`, Up: `[0, 1, 0]`).\n    * **Projection:** Use `mat4.perspective`. (FOV: $\\frac{\\pi}{4}$ radians, Aspect: canvas width/height, Near: 0.1, Far: 100.0).\n4. **Render Loop:**\n    * Use `requestAnimationFrame`.\n    * Clear both color and depth buffers.\n    * Update the model matrix (rotate it slightly every frame around a unit-length axis vector using `mat4.rotate`).\n    * Upload the model matrix via `gl.uniformMatrix4fv`.\n    * Draw 36 vertices using `gl.TRIANGLES`.\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eSolution:\u003c/strong\u003e\u003c/summary\u003e\n\nThe solution below moves the WebGL utility functions `createShader()` and `createProgram()` into their own file.\n\n\u003cstrong\u003e\u003ccode\u003eindex.html\u003c/code\u003e:\u003c/strong\u003e\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e\n    \u003ctitle\u003eSpinning cube\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003ccanvas id=\"spinning-cube-canvas\" width=\"400\" height=\"400\"\u003e\n      A canvas with a spinning cube.\n    \u003c/canvas\u003e\n    \u003cscript src=\"libs/gl-matrix-min.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"webgl-utilities.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"spinning-cube.js\"\u003e\u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n\u003cstrong\u003e\u003ccode\u003espinning-cube.js\u003c/code\u003e:\u003c/strong\u003e\n```js\n// GET CONTEXT\nconst canvas = document.getElementById('spinning-cube-canvas');\nconst gl = canvas.getContext('webgl2');\n\n// SET CANVAS BACKGROUND COLOR\nconst lightGray = [220 / 255, 220 / 255, 220 / 255, 1];\ngl.clearColor(...lightGray);\n\n// LOAD CUBE DATA\nconst positions = getCubePositions();\nconst colors = getCubeColors();\n\n// CREATE MATRICES\nconst uModel = glMatrix.mat4.create();\n\nconst uView = glMatrix.mat4.create();\nconst eye = glMatrix.vec3.fromValues(0, 0, 4);\nconst center = glMatrix.vec3.fromValues(0, 0, 0);\nconst up = glMatrix.vec3.fromValues(0, 1, 0);\nglMatrix.mat4.lookAt(uView, eye, center, up);\n\nconst uProjection = glMatrix.mat4.create();\nconst fovy = Math.PI / 4;\nconst aspect = canvas.width / canvas.height;\nconst near = 0.1;\nconst far = 100.0;\nglMatrix.mat4.perspective(uProjection, fovy, aspect, near, far);\n\n// CREATE SHADER SOURCE\nconst vsSource = `#version 300 es\nlayout(location = 0) in vec3 position;\nlayout(location = 1) in vec3 color;\nuniform mat4 uModel;\nuniform mat4 uView;\nuniform mat4 uProjection;\nout vec3 vColor;\n\nvoid main() {\n  gl_Position = uProjection * uView * uModel * vec4(position, 1.0);\n  vColor = color;\n}\n`;\n\nconst fsSource = `#version 300 es\nprecision highp float;\nin vec3 vColor;\nout vec4 fragColor;\n\nvoid main() {\n  fragColor = vec4(vColor, 1.0);\n}\n`;\n\n// MANAGE STATE: VAO AND VBO\nconst vao = gl.createVertexArray();\ngl.bindVertexArray(vao);\n\nconst positionVBO = gl.createBuffer();\ngl.bindBuffer(gl.ARRAY_BUFFER, positionVBO);\ngl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);\ngl.enableVertexAttribArray(0);\ngl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);\n\nconst colorVBO = gl.createBuffer();\ngl.bindBuffer(gl.ARRAY_BUFFER, colorVBO);\ngl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);\ngl.enableVertexAttribArray(1);\ngl.vertexAttribPointer(1, 3, gl.FLOAT, false, 0, 0);\n\n// CREATE AND ACTIVATE PROGRAM\nconst program = createProgram(gl, vsSource, fsSource);\ngl.useProgram(program);\n\n// ACTIVATE 3D OPERATIONS\ngl.enable(gl.DEPTH_TEST);\ngl.enable(gl.CULL_FACE);\n\n// GET MATRIX LOCATIONS\nconst uModelLocation = gl.getUniformLocation(program, 'uModel');\nconst uViewLocation = gl.getUniformLocation(program, 'uView');\nconst uProjectionLocation = gl.getUniformLocation(program, 'uProjection');\n\n// SET STATIC MATRICES\ngl.uniformMatrix4fv(uViewLocation, false, uView);\ngl.uniformMatrix4fv(uProjectionLocation, false, uProjection);\n\n// CREATE AXIS OF ROTATION (a unit vector indicates the direction of the axis)\nconst axis = glMatrix.vec3.fromValues(1, 1, 0);\nglMatrix.vec3.normalize(axis, axis);\n\nlet startTime;\n\n// Tell WebGL how to map the Normalized Device Coordinates (NDC) \n// of the clip space (-1 to +1) to pixel coordinates on the screen.\n// Required if the canvas is resized after the context is created.\ngl.viewport(0, 0, canvas.width, canvas.height);\n\n// ANIMATE\nfunction draw(timestamp) {\n  if (!startTime) {\n    startTime = timestamp;\n  }\n  \n  const elapsedTime = timestamp - startTime;\n\n  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n\n  // Rotate based on elapsed time (0.001 converts ms to seconds)\n  glMatrix.mat4.identity(uModel); \n  glMatrix.mat4.rotate(uModel, uModel, elapsedTime * 0.001, axis);\n  gl.uniformMatrix4fv(uModelLocation, false, uModel);\n\n  gl.drawArrays(gl.TRIANGLES, 0, 36);\n\n  requestAnimationFrame(draw);\n}\n\nrequestAnimationFrame(draw);\n\n// CUBE LOADERS\nfunction getCubePositions() {\n  // 36 vertices (x, y, z)\n  return new Float32Array([\n      // Front face\n      -0.5, -0.5,  0.5,\n      0.5, -0.5,  0.5,\n      0.5,  0.5,  0.5,\n      -0.5, -0.5,  0.5,\n      0.5,  0.5,  0.5,\n      -0.5,  0.5,  0.5,\n\n      // Back face\n      -0.5, -0.5, -0.5,\n      -0.5,  0.5, -0.5,\n      0.5,  0.5, -0.5,\n      -0.5, -0.5, -0.5,\n      0.5,  0.5, -0.5,\n      0.5, -0.5, -0.5,\n\n      // Top face\n      -0.5,  0.5, -0.5,\n      -0.5,  0.5,  0.5,\n      0.5,  0.5,  0.5,\n      -0.5,  0.5, -0.5,\n      0.5,  0.5,  0.5,\n      0.5,  0.5, -0.5,\n\n      // Bottom face\n      -0.5, -0.5, -0.5,\n      0.5, -0.5, -0.5,\n      0.5, -0.5,  0.5,\n      -0.5, -0.5, -0.5,\n      0.5, -0.5,  0.5,\n      -0.5, -0.5,  0.5,\n\n      // Right face\n      0.5, -0.5, -0.5,\n      0.5,  0.5, -0.5,\n      0.5,  0.5,  0.5,\n      0.5, -0.5, -0.5,\n      0.5,  0.5,  0.5,\n      0.5, -0.5,  0.5,\n\n      // Left face\n      -0.5, -0.5, -0.5,\n      -0.5, -0.5,  0.5,\n      -0.5,  0.5,  0.5,\n      -0.5, -0.5, -0.5,\n      -0.5,  0.5,  0.5,\n      -0.5,  0.5, -0.5,\n  ]);\n}\n\nfunction getCubeColors() {\n  // 36 colors (r, g, b)\n  // Colors match faces (e.g., first 6 vertices are red, next 6 are green, etc.)\n  return new Float32Array([\n      // Front: Red\n      1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,\n      // Back: Green\n      0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,\n      // Top: Blue\n      0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,\n      // Bottom: Yellow\n      1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,\n      // Right: Purple\n      1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,\n      // Left: Cyan\n      0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,\n  ]);\n}\n```\n\n\u003cstrong\u003e\u003ccode\u003ewebgl-utilities.js\u003c/code\u003e:\u003c/strong\u003e\n```javascript  \n// CREATION UTILITIES: SHADERS AND PROGRAM \nfunction createShader(gl, type, source) {\n  const shader = gl.createShader(type);\n  gl.shaderSource(shader, source);\n  gl.compileShader(shader);\n  \n  // Check success\n  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n    const shaderInfoLog = gl.getShaderInfoLog(shader);\n    gl.deleteShader(shader);\n    throw new Error(`Could not compile shader: ${shaderInfoLog}`);\n  }\n  return shader;\n}\n\nfunction createProgram(gl, vsSource, fsSource) {\n  const vs = createShader(gl, gl.VERTEX_SHADER, vsSource);\n  const fs = createShader(gl, gl.FRAGMENT_SHADER, fsSource);\n  \n  const program = gl.createProgram();\n  gl.attachShader(program, vs);\n  gl.attachShader(program, fs);\n  gl.linkProgram(program);\n  \n  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n    const programInfoLog = gl.getProgramInfoLog(program);\n    gl.deleteProgram(program);\n    throw new Error(`Could not link program: ${programInfoLog}`);\n  }\n  return program;\n}\n```\n\n\u003c/details\u003e\n\n# Community \u0026 next steps\n\n**🤗 Community:**\n\nWant to share your progress, ask questions, provide feedback, or share your favorite resources? Drop a link in the [\"Show and tell\" discussion thread](https://github.com/GregStanton/webgl2-glsl-primer/discussions/1)!\n\n**🚀 Next steps:**\n\nNow that you have the irreducible minimum of the programmable geometry pipeline memorized, you are ready to build. You can use the following resources to apply your skills to solve specific implementation problems, to deepen your theoretical understanding, or to build advance","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGregStanton%2Fwebgl2-glsl-primer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGregStanton%2Fwebgl2-glsl-primer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGregStanton%2Fwebgl2-glsl-primer/lists"}