15
CS 450: COMPUTER GRAPHICS PORTRAIT OF AN OPENGL PROGRAM SPRING 2015 DR. MICHAEL J. REALE

CS 450: COMPUTER GRAPHICS PORTRAIT OF AN OPENGL PROGRAM SPRING 2015 DR. MICHAEL J. REALE

Embed Size (px)

Citation preview

CS 450: COMPUTER GRAPHICS

PORTRAIT OF AN OPENGL PROGRAM

SPRING 2015

DR. MICHAEL J. REALE

INTRODUCTION

• We’re going to talk a little bit about the structure and logic of a basic, interactive OpenGL/GLUT program

• In the long-standing tradition of legal documents and license agreements, we will hereafter refer to this specific kind of program as “THE PROGRAM”

BIRD’S EYE VIEW

• The code in our program has three basic sections:

• Initialization

• Stuff we need to do only once

• Stuff we need to create once

• Drawing

• Clear buffer

• Prepare to draw stuff on window

• Actually draw stuff on window

• (Swap buffers)

• Sleep

• Interaction Logic

• What do we do when the mouse does something?

• What do we do when a certain key is pressed?

DRAWING SOMETHING IN OPENGL

• Let’s say we want to draw an “object”

• E.g., a triangle, a polyline, a list of pixels

• To draw an object in our program, we will need two things:

• 1) Lists/arrays of information describing our object “local copy” at minimum:

• A list of vertex positions (e.g., vertices of a triangle, vertices of the polyline, pixels we want to draw)

• A list of colors per vertex

• (Optional) A list of the indices for the vertices we want to use

• 2) An OpenGL buffer object for each list/array for each object, we will need to:

• Create the buffer object glGenBuffers()

• Bind buffer and allocate / copy in data glBindBuffer(), then glBufferData()

• Bind buffer and attach to attribute array glBindBuffer(), then glVertexAttribPointer()

INITIALIZATION STAGE: REQUIRED

• I am assuming that you have done all of the GLUT and GLEW specific stuff already

• Stuff that should ONLY be done once:

• Create Vertex Array Object (VAO) glGenVertexArrays(), then glBindVertexArray()

• Load the shader code and compile the shader program

• Returns shader program ID

• Get any uniform variable IDs we will use later

• These will not change per program

• Create our buffers glGenBuffers()

• Creates an ID for each buffer just need to do this once

INITIALIZATION STAGE: OPTIONAL (1)

• Depending on our application, we may decide to put some things in the initialization stage (rather than in the drawing loop or logic code)

• If we have an object we want to draw that WILL NOT CHANGE:

• Bind and copy in / allocate data glBindBuffers(), then glBufferData()

• Data will not change, so can just copy into buffers once and be done with it

• NOTE: There is nothing preventing you from doing this again in the drawing loop, however

• If we have only ONE shader program:

• Turn on shader program once and never turn it off glUseProgram()

INITIALIZATION STAGE: OPTIONAL (2)

• If we are using the same shader program AND we are ALWAYS going to use the SAME buffers (i.e., just drawing ONE object):

• Turn on shader program glUseProgram()

• Enable attribute arrays glEnableVertexAttribArray()

• Attach buffers to attribute arrays glBindBuffer(), then glVertexAttribPointer()

• NOTE: You CANNOT put this in init() if you have DIFFERENT objects you want to draw:

• Will have to attach a different buffer to each attribute array

• ALSO NOTE: You have to attach the buffers to attribute arrays for each shader program

• So, if you attach them while ShaderProg1 is active, then try to draw with ShaderProg2, it won’t work

INITIALIZATION STAGE: OPTIONAL (3)

• If our model-view-projection matrix is NEVER going to change:

• Set up our matrices with GLM

• Copy in MVP matrix to shader program glUniformMatrix4fv()

• NOTE: You CANNOT put this in init() if:

• You want to change the projection matrix if the screen resizes (glViewport() is OK, however)

• You want to allow the user to move/rotate the camera

• You want to use different model transformations on different objects (i.e., transform objects)

DRAWING LOOP

• The drawing loop will execute over and over again if we passed the drawing function to glutIdleFunc()

• Basic Steps:

• Clear buffer glClear()

• Prepare to draw stuff on window

• Set up matrices with GLM (unless you decided to do so ONCE in init())

• Bind and copy in updated data for buffers glBindBuffers, then either glBufferData() or glBufferSubData()

• If data does NOT change, then can do this ONCE in init() instead

• Actually draw stuff on window

• (Swap screen buffers)

• If using double-buffering

• Sleep

DRAWING LOOP: ACTUALLY DRAWING THINGS• What goes here depends on what you’ve put in init()

• At minimum, you would just have glDrawArrays() or glDrawElements()

• Everything else already set up in init()

• At maximum:

• Turn on shader program glUseProgram()

• Enable attribute arrays glEnableVertexAttribArray()

• Attach buffers to attribute arrays glBindBuffer(), then glVertexAttribPointer()

• (OPTIONAL) Bind buffer as index array glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, … )

• Draw the object glDrawArrays() or glDrawElements()

• You can also deactivate the shader program, attribute arrays, and bindings afterwards if you so desire

DRAWING LOOP: HOW MANY VERTICES DO WE DRAW FROM OUR OBJECT?

• If we want to draw ALL the vertices glDrawArrays()

• If we want to draw SPECIFIC vertices, need:

• List of indices to draw AND buffer object to hold indices

• Bind buffer and copy in data glBindBuffer(), then glBufferData()

• Bind buffer to GL_ELEMENT_ARRAY_BUFFER

• Draw with glDrawElements()

DRAWING LOOP: ZOOMED OUT

• With respect to an object that will change, the drawing loop looks like this:

• Clear (and possibly matrix setup)

• Update buffer data

• Draw

• (Swap)

• Sleep

• How you update your buffer data depends on your application:

• Example:

• Clear local list of pixels

• Recalculate all pixels you wish to draw

• Copy pixel list into buffer

• REMEMBER: The drawing loop is repeated constantly! Keep that in mind when adding/clearing lists in the loop!

INTERACTION LOGIC

• GLUT handles events in an asynchronous fashion

• You can approach interaction logic in two ways:

• 1) Perform actions inside GLUT mouse/keyboard functions

• E.g., add vertex to list when mouse is clicked INSIDE mouse function

• OR

• 2) Have global mouse/keyboard state variables, and check the values of these variables in the drawing loop

• E.g., save mouse coordinates in mouse moving function check what do to with mouse coordinates in main drawing loop

SAVING WORK

• The screen/window will be cleared 30-60 times a second!

• So, if you draw a line on one iteration, you need to redraw it again on the next iteration means you need to save the information needs to draw said line (i.e., endpoints of the line)

• Think about what you’re doing when updating either your local copy of your object OR the OpenGL buffers!

• If you add points to a list in the draw loop, either:

• Clear the list and add the points again every iteration

• OR

• Don’t clear the list but make sure you only add the points ONCE

• May be stuck with the first option if you have to CHANGE points in the list

UPDATING BUFFERS

• You have two options with updating buffer data:

• Copy in EVERYTHING (or EVERYTHING + MORE) glBufferData()

• Change some or all of buffer data (but CANNOT add new stuff) glBufferSubData()

• You CANNOT just append items to a buffer you will have to append items to your local copy, then use glBufferData() to reallocate/copy in data