BASIC RENDERING CS 4363/6353 THE GRAPHICS PIPELINE OVERVIEW • Vertex Processing • Coordinate transformations • Compute color for each vertex • Clipping and Primitive Assembly • Assemble sets of vertices into lines and polygons • Clipping volume culls out geometry outside, and clips geo that straddles • Rasterization • Determine which pixels are inside each polygon (primitive) • The output is a set of fragments for each primitive • Fragment Processing • Fills in the pixels in the frame buffer (what you’re seeing right now!) SHADERS (FROM 100,000 FEET. WELL, MAYBE 10,000 FEET) • Shaders: • Expose the programmable pipeline ! • Allow us to manipulate vertices and pixel colors • Look very similar to C • void main() • Must be compiled and linked from source • Generally have two shaders: • Vertex shader (to handle vertex transformations and lighting) • Fragment shaders (to handle per-pixel operations like lighting to determine color) • Hundreds (or thousands) of GPUs are available SHADERS AND PASSING DATA • Must feed shaders some data! Three ways to pass. • Attributes (vertex shaders only): • data that changes per vertex • A four component vector (regardless if you use it or not) • Copied from your OpenGL program into a buffer • Uniforms (vertex/fragment shaders): • A single value that is shared for all attributes • Common for transformation matrices (vertex shader) • Texture (mostly fragment shaders): • Used for texture data SIMPLE VERTEX EXAMPLE #version 150 in vec4 vPosition; // This data is from your OpenGL code void main () { gl_Position = vPosition; } SIMPLE FRAGMENT SHADER #version 150 out vec4 fColor; void main () { fColor = vec4(1.0, 0.0, 0.0, 1.0); } // Hard-coded red! SHADERS AND PASSING DATA • outs/ins • Used for passing data between shaders • Client (OpenGL code) has no access to these variables • Vertex shader’s out variable corresponds to the fragment shader’s in variable. RENDERING OPTIONS • We typically create a single batch of vertices to draw • We generally set up all “features” before drawing anything • State machine mentality • We always have vertices, but we can render them in 7 different ways • GL_POINTS • GL_LINES • GL_LINE_STRIP • GL_LINE_LOOP • GL_TRIANGLES** • GL_TRIANGLE_STRIP • GL_TRIANGLE_FAN RENDERING OPTIONS (GL_POINTS) • Can change the point sizes, but not important right now • Points are always square unless anti-aliased RENDERING OPTIONS (GL_LINES) • Connects in pairs (line segments), so should have an even number of points • Change line width with glLineWidth (GLfloat width); RENDERING OPTIONS (GL_LINE_STRIP) • In a connect-the-dots fashion, draw from one vertex to another • How would you do this with GL_LINES? RENDERING OPTIONS (GL_LINE_LOOP) • Closes the loop • Is typically what you would use for outlines/tracing RENDERING OPTIONS (OTHERS) • Some of these are allowed… RENDERING OPTIONS (OTHERS) • Some of these aren’t… • NO QUADS! Triangles only… V1 TRIANGLE WINDING • Simply means the order of the vertices you specify • Clockwise • Counter-Clockwise • V0 V2 Why is this important? V2 • Clockwise is back facing • Counter-clockwise is front facing • Long story short: • If you specify in reverse order, sometimes you won’t see anything or it will be reversed • Can reverse using glFrontFace (GL_CW); V0 V1 TRIANGLE STRIPS • Specify the first triangle (V 0, V1, V2) V2 V0 V1 TRIANGLE STRIPS • Specify the first triangle (V 0, V1, V2) • The next vertex (V 3) creates a new triangle (V 1, V2, V3) V2 V0 V3 V1 TRIANGLE STRIPS • Specify the first triangle (V 0, V1, V2) • The next vertex (V 3) creates a new triangle (V 1, V2, V3) • The next vertex (V 4) creates a new triangle (V 2, V3, V4) V4 V2 V0 V3 V1 EXAMPLE • From Wikipedia… TRIANGLE FANS • Can create a fan where V 0 is the central vertex • Specify first triangle, then each new vertex is a wedge of the fan V2 V0 V1 TRIANGLE FANS • Can create a fan where V 0 is the central vertex • Specify first triangle, then each new vertex is a wedge of the fan • Still uses V 0 V3 V2 V0 V1 TRIANGLE FANS • Can create a fan where V 0 is the central vertex • Specify first triangle, then each new vertex is a wedge of the fan • Still uses V0 V3 V2 V4 V0 V1 EXAMPLE OF TRIANGLE FAN CULLING AND DEPTH TESTING • You’re going to be drawing a lot of triangles • What happens if you draw one triangle on top of another? • What if the second triangle is far away? • Sort triangles of an object (painter’s algorithm)? • What about several objects on the screen? • Also, should you be able to see the inside of geometry? • Basically, there are two problems: • Unseen triangles are unlit • The depth of the triangles is important HOUSTON, WE HAVE A PROBLEM (IMAGE FROM OPENGL SUPERBIBLE) • Sometimes rendering the far-side triangles (which are unlit) BACKFACE CULLING • Simply means “Don’t draw triangles that don’t face the camera” • Two steps in OpenGL • glEnable (GL_CULL_FACE); • glCullFace (GL_BACK); • glCullFace could also use: • GL_FRONT • GL_FRONT_AND_BACK CULLING THE BACKFACE(S) • Problem solved? BUT WAIT! (IMAGES FROM OPENGL SUPERBIBLE) DEPTH TESTING • Just because we culled the back-facing triangles doesn’t mean they’re sorted! • Depth testing: • Removes hidden surfaces • Each pixel has a depth (z-value) • Higher values mean closer to the camera • This value is stored in the depth buffer • glEnable (GL_DEPTH_TEST); • Is this starting to make sense? glutInitDisplayMode (GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH); POLYGON RENDERING MODES • Polygons do not have to be filled • We have 3 modes to draw polygons: • GL_FILL – what we’ve been using • GL_LINE – 3D wireframe • GL_POINT – just the vertices • Call glPolygonMode() to change rendering value: // renders front and back facing polys in wireframe glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); GL_LINE • Backface culling and depth testing are turned on A NOTE ABOUT POLYGON OFFSET • You can skip it • Sometimes draw two triangle very close to the same depth (called decaling) • This creates “z-fighting” • Part of the further polygon shows • Before rendering closer triangle: glEnable (GL_POLYGON_OFFSET_LINE); glPolygonOffset(-1.0f, -1.0f); SCISSOR TEST • We won’t be using this in our code, but: • Used to increase performance • Updates only the portion within a defined area (i.e. doesn’t update anything outside of that area) • By default, scissor test is the size of the window • Use glScissor (int x, int y, int width, int height): glEnable (GL_SCISSOR_TEST); glScissor (100, 100, 600, 400); // only render in that area BLENDING • Without depth testing, color values overwrite one another • With depth testing, new fragments may replace old ones • Discards further fragments • This no longer happens with OpenGL blending: glEnable (GL_BLENDING); • Remember, each color has a red, green, blue and alpha! SPECIFYING HOW TO BLEND • We must specify how the blending occurs • Destination color is the color already in the color buffer • Source color is the one we’re about to write into the color buffer Cf = (Cs * S) + (C d * D) • Where: • Cf is the final color, C s is the source color and C d is the destination color • S is the source blending factor • D is the destination blending factor MOST COMMON METHOD • glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); • Take source and multiply rgb (colors) by its alpha value • Take destination and multiply rgb by (1-source alpha) • Example: • Cd = (1.0f, 0.0f, 0.0f, 1.0f) //Red • Cs = (0.0f, 0.0f, 1.0f, 0.6f) // Blue, with source alpha 0.6 • D = 1.0f – 0.6 == 0.4f • Cf = (Blue*0.6) + (Red*0.4) EXAMPLE ONE FINAL NOTE • We can change the underlying equation as well using glBlendEquation(): • GL_FUNC_ADD Cf = (Cs*S)+(Cd*D) • GL_FUNC_SUBTRACT Cf = (Cs*S)-(Cd*D) • GL_FUNC_REVERSE_SUBTRACT Cf = (Cd*D) - (Cs*S) • GL_MIN Cf = min(Cs,Cd) • GL_MAX Cf = max(Cs,Cd) ANTIALIASING • We have square pixels, which make the image look computer-generated • The visual aspect of this is called “the jaggies” • To eliminate, OpenGL uses blending of source with surrounding destination pixels • So: glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); • Then: glEnable (GL_POINT_SMOOTH); // and/or glEnable (GL_LINE_SMOOTH); // and/or glEnable (GL_POYGON_SMOOTH); // ** // ** outdated or not supported at all! EXAMPLE MULTISAMPLING • Helps to smooth out polygons • Creates another buffer (color, depth and stencil) • All primitives are sampled multiple times, then “averaged” • You take a performance hit here, but looks good! • Point/Line antialiasing is disable when multisampling is enabled • First: glutInitDisplayMode (GLUT_DOUBLE| GLUT_RGB| GLUT_DEPTH| GLUT_MULTISAMPLE); • Then: glEnable (GL_MULTISAMPLE);