class: center, middle # Creación de Videojuegos ### 3D Graphics --- class: center, middle # Triangles
--- # Some definitions * Vertex (plural Vertices): A point in 3D space * Triangle: Three vertices * Face: The "front" side of a triangle * Normal: A vector that points "away" from the face --- # Why triangles? * Triangles are always flat * Flat makes it easier to calculate lighting, color, etc. * Triangles are convex * Convex makes it easier to interpolate between the vertices * Any polygon can be divided into triangles --- # Color * We can assign a color to a triangle * But what if we want to have different colors? * Ideally, we want a gradual change * Idea: Assign color to the vertices and interpolate * It's such a good idea, 3D libraries have it built-in --- # Interpolation Halfway between two values: $$ p = \frac{r + s}{2} = \frac{1}{2} r + \frac{1}{2}s$$ Closer to r than to s $$ p = \frac{2}{3} r + \frac{1}{3} s$$ or, generally: $$ p = \theta \cdot r + (1- \theta) \cdot s$$ --- # Interpolation What if we have more than two values? $$ p = \theta \cdot r + \phi \cdot s + \psi \cdot t$$ with $$\theta + \phi + \psi = 1$$ Note: r, s, and t don't have to be numbers, they could also be vectors! In particular, they can be the vertices of a triangle. Every point in the triangle can then be represented as $$p = (\theta,\phi,\psi)$$ --- # Barycentric coordinates
image/svg+xml
Barycentric Coordinates in a triangle
(1,0,0)
(0,1,0)
(0,0,1)
(1/2,1/2,0)
(1/2,0,1/2)
(0,1/2,1/2)
(1/4,1/4,1/2)
(1/4,1/2,1/4)
(1/2,1/4,1/4)
(1/3,1/3,1/3)
--- # Interpolation What can we do with this representation? $$p = (\theta,\phi,\psi)$$ Calculate color values! $$c(p) = \theta \cdot c(r) + \phi \cdot c(s) + \psi \cdot c(t)$$ --- # A colored triangle
--- class: medium # Normals * Normals are (unit) vectors that point away from a face * They are used for lighting (we'll discuss how next week) * What does "away" mean? * Simplest case: perpendicular to the triangle * What if we have adjacent triangles? * We can assign normals to each vertex and interpolate, just as with colors --- # Textures * Colored triangles are boring! * What if we want to show something like wood? * Use an image as the texture * Assign texture (uv) coordinates to each vertex * *Interpolate* between the vertices to get the uv coordinate for each pixel! --- # Textured Triangle Texture coordinates (uv): (0,0), (1,1), (1,0)
--- # Textured Triangle Let's use (0.5,0.5) as the UV value for one vertex.
--- # Meshes * Triangles are boring! * A *Mesh* is a collection of triangles (and normals, uv coordinates, colors) * How about something more exciting, like a cube? * We can assemble a cube out of triangles! * Or a bunny! --- # Stanford Bunny
--- class: small # Back to the cube * Cubes have 8 vertices and 6 faces (12 triangles!) * Vertices: - v1 = (0,0,0) - v2 = (1,0,0) - v3 = (0,1,0) - v4 = (1,1,0) - v5 = (0,0,1) - v6 = (1,0,1) - v7 = (0,1,1) - v8 = (1,1,1) * Faces: - f1: (v1,v2,v3) - f2: (v3,v2,v4) - etc. --- class: small # The .obj file format
v 0 0 0
v 1 0 0
v 0 1 0
v 1 1 0
v 0 0 1
v 1 0 1
v 0 1 1
v 1 1 1
f 2 1 3
f 2 3 4
f 8 5 6
f 5 8 7
f 6 1 2
f 1 6 5
f 3 8 4
f 8 3 7
f 1 7 3
f 7 1 5
f 8 2 4
f 2 8 6
Download file
here
--- # .obj files * List of vertices, faces, uv coordinates, normals, etc. * You could hand-write one (like for the cube!) * Or you write code to generate the file * Unity (and most other 3D software) reads them! --- # Cube (Controls: w, a, s, d)
--- # Level of Detail * Many modern meshes have a lot of detail * But what if it is far away? * Idea: Use a lower-resolution (fewer triangles) version of the same mesh! * Can often be precomputed automatically * Limitation: Visible "jumping" when the low-res mesh is replaced with the higher-res one --- # Stanford Bunny and Level of Detail
--- class: small # Billboards * Many background objects like trees, grass, rocks only exist as decoration * It may not be important for them to have a lot of detail * Actually, as long as it looks like a tree from all sides, it's probably fine * Just show a picture of a tree, and turn it so it always faces the camera! * Also useful for health bars or similar information ``` transform.LookAt(2 * transform.position - Camera.main.transform.position);``` --- class: center, middle # Rendering Pipeline ## Or: How do we actually get something onto the screen --- class: small # Rendering * Model coordinates need to be translated to world coordinates (where is the mesh) * World coordinates are then translated to Camera coordinates (where in the field of view of the camera is the mesh?) * The Camera coordinates need to be projected onto a Viewport (objects that are further away become smaller) * The Viewport is then mapped onto a window on the screen * We will discuss the math behind this next week --- # Camera
--- # Clipping and Culling * Many triangles do not need to be rendered * Anything outside the frustum or not facing the camera can be discarded (Frustum culling and backface culling) * Triangles that are behind other triangles can also be culled (Occlusion culling) * Triangles that are partially inside the frustum have to be clipped (cut into pieces) --- class: small # Backface culling * How do we recognize what is facing away from the camera? * Assume a and b are unit vectors $$ \vec{a} \cdot \vec{b} = \cos(\theta) $$ * The cosine is negative iff the vectors point in opposite directions * Discard any triangle where the face normal points in the same direction as the (unit) vector pointing from the camera to the triangle --- class: small # Painter's algorithm * How do we avoid showing triangles that are occluded? * When you paint, whatever you draw last is visible on the canvas * Let's use the same idea with triangles! * Draw triangles starting with the one furthest from the camera * The closer a triangle is to the viewer, the later it is drawn * If a triangle is partially occluded, you will still see the rest --- # Which order?
--- class: small # z-Buffer * Instead of deciding per triangle, decide per pixel * Store z-coordinate (depth) in a special buffer * When something would be drawn on a pixel: - If the z-coordinate of the new object is greater than the buffer, don't draw - Otherwise draw, and update the buffer * The z-Buffer usually exists in hardware --- class: small # Occlusion culling * Both of these approaches still attempt to draw everything * In large scenes this can be very expensive * Specialized algorithms exist to determine objects that are occluded * Such objects can be culled entirely * Unity has an Occlusion culling algorithm, but it requires some setup --- class: small # Shaders * Shaders are little programs that can change draw operations * Vertex shaders operate on vertices * Geometry shaders operate on primitives (triangles) * Fragment shaders operate on fragments (drawable parts) * Compute shaders can be used to do calculations on the GPU * More next week --- # Rendering: Shaders
--- # References * [Barycentric coordinate system](https://en.wikipedia.org/wiki/Barycentric_coordinate_system) * [NeHe OpenGL tutorials](http://nehe.gamedev.net/) (slightly outdated, but explains the basics well) * [OpenGL Billboard tutorial](http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/billboards/) * [three.js](https://threejs.org/) (JavaScript library for easy 3D rendering) * [OpenGL Render Pipeline](https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview)