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 --- class: smallp # An Example Consider the triangle $$ a = (2,2,3), b = (3,3,4), c = (3,1,3) $$ with the normal vector $$ \vec{n} = \begin{pmatrix} \frac{-1}{\sqrt{6}} \\\\ \frac{-1}{\sqrt{6}} \\\\ \frac{2}{\sqrt{6}} \end{pmatrix} $$ and a point $$ p = (3\sqrt{6},0, 2\sqrt{6}) $$ ## Does the point p lie in front of or behind the triangle? --- # 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
--- # An example Consider the triangle $$ a = (1,0,0), b = (1,1,0), c = (0,1,0) $$ ## If a has the color (99,0,0), b has the color (0,39,0), and c has the color (0,81,81), what color does the barycenter of the triangle have using linear interpolation? Which color does the point that is twice as close to a as to b and c (in the barycentric sense) have? --- 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.
--- # An example Consider the triangle $$ a = (2,1,3), b = (4,3,4), c = (3.5,2.5,4.5) $$ The texture coordinates are $$ t(a) = (\frac{3}{5}, \frac{3}{8}), t(b) = (\frac{3}{10}, \frac{3}{16}), t(c) = (\frac{3}{7}, \frac{3}{10}) $$ ## The point p is the closest point to c on the line from a to b. What texture coordinates does p have? --- # 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: center, middle # Shaders
--- class: small # Shaders * Shaders are little programs that can change draw operations * Vertex shaders operate on vertices * Geometry shaders operate on primitives (triangles) * Fragment/pixel shaders operate on fragments (drawable parts) * Compute shaders can be used to do calculations on the GPU * Written in a Shader Language --- # Shader languages * ARB assembly (legacy) * Cg (deprecated) * GLSL (OpenGL) * HLSL (DirectX, used by Unity) * Tool: HLSL2GLSL --- # HLSL Shaders ```HLSL Shader "ShaderName" { Properties { // Properties you can set in Unity } SubShader { // Shader code } } ``` --- # HLSL Shader properties ```HLSL Properties { _MyTexture ("My texture", 2D) = "white" {} _MyInt ("My integer", Int) = 2 _MyFloat ("My float", Float) = 1.5 _MyRange ("My range", Range(0.0, 1.0)) = 0.5 _MyColor ("My color", Color) = (1, 0, 0, 1) // (R, G, B, A) _MyVector ("My Vector4", Vector) = (0, 0, 0, 0) // (x, y, z, w) } ``` --- # HLSL Shader properties as ```HLSL SubShader { sampler2D _MyTexture; // 2D = sampler2D int _MyInt; float _MyFloat; float _MyRange; half4 _MyColor; // Color = half4 float4 _MyVector; // Vector = float4 // Code } ``` --- class: small # Vertex and Pixel Shader ```HLSL Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag struct vertInput { float4 pos : POSITION; }; struct vertOutput { float4 pos : SV_POSITION; }; vertOutput vert(vertInput input) { vertOutput o; o.pos = mul(UNITY_MATRIX_MVP, input.pos); return o; } half4 frag(vertOutput output) : COLOR { return half4(1.0, 0.0, 0.0, 1.0); } ENDCG } ``` --- class: small # What can you pass in and out of these shaders? * Possible inputs: - `POSITION` - `NORMAL` - `COLOR` - `TEXCOORD0`, `TEXCOORD1`, ... - etc. * Possible outputs: - `SV_POSITION` - `COLOR` - `TEXCOORD0`, `TEXCOORD1`, ... - etc. --- class: small # What can you do? * Vertex Shader: - Change positions of vertices - Modify texture coordinates - Store information for the pixel shader * Pixel Shader: - Change how a pixel is drawn - Add noise or distortion effects (water, glass) --- class: small # How do you use a Shader in Unity? * Create a new Asset: - Surface Shader - Unlit Shader for a Vertex *and* Pixel Shader * On your material, select your Shader from the dropdown box
--- class: small # Wobbling In the Vertex Shader: ```HLSL fixed4 col = tex2Dlod(_NoiseTex, float4(v.uv, 0, 0)); float d = 1 - (v.uv[1]*v.uv[1] + v.uv[0]*v.uv[0]) + col[0]; o.vertex = UnityObjectToClipPos(v.vertex + float4(0.0, 0.5*(sin(_Time[2] + d*8) / 2 + 0.5), 0.0, 0.0)); o.tex = float4(d,0,0,0); ``` In the Pixel Shader: ```HLSL fixed4 col = float4(0, 0, (sin(_Time[2] + i.tex[0]*8)/2 + 0.5),1); ``` --- # Wobbling: Result
Shader source code
--- class: medium # References * Book: *Mathematics for Game Developers*, by Christopher Tremblay * [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) * [Vertex and Fragment shaders in Unity](https://www.alanzucconi.com/2015/07/01/vertex-and-fragment-shaders-in-unity3d/)