wilf lalonde @2012 comp 4501 95.4501 opengl odds and ends
TRANSCRIPT
Wilf LaLonde @2012Comp 4501
95.450195.4501
OpenGL
Odds and Ends
Wilf LaLonde @2012Comp 4501
Odds and EndsOdds and Ends
• A few odds and ends to help with assignment #3 particularly issues that might trip you.
• A bit about blending.• A bit about OpenGL stacks.• A bit about OpenGL shaders.
Generally, things you SHOULD be able to figure out by yourself but might not have.
Wilf LaLonde @2012Comp 4501
95.400295.4002
Transformation
Extensions
Wilf LaLonde @2012Comp 4501
• There is a lookAtForObject which can build an entire transformation for you…
• If you need the inverse (for something playing the role of a camera), it might be nice to have a version call lookAtForCamera.
• The next slide provides it… IF YOU NEED IT.
A Useful Addition To TransformationA Useful Addition To Transformation
Wilf LaLonde @2012Comp 4501
//In .h filestatic Transformation lookAtForCamera (const Point &from, const Vector
&direction, const Vector &up, const Vector &alternateUp) ;
//In .cpp fileTransformation Transformation::lookAtForCamera (const Point &from,
const Vector &direction, const Vector &up, const Vector &alternateUp) {//This version returns the same thing as gluLookAt but computes it without using the stack...//Note: up is an approximate yAxis. If it is erroneously directed into the z-direction, use alternateUp instead.Vector zAxis = -direction.normalized ();Vector xAxis = (up.cross (zAxis)).normalized ();if (xAxis.isZero ()) xAxis = (alternateUp.cross (zAxis)).normalized ();Vector yAxis = zAxis.cross (xAxis);Transformation result; //Compute the inverse of rotateToAxes (xAxis, yAxis, zAxis, from) which interpreted as RT means computing T-1R-1.result.set (
xAxis.x, yAxis.x, zAxis.x, 0.0,xAxis.y, yAxis.y, zAxis.y, 0.0,xAxis.z, yAxis.z, zAxis.z, 0.0,-from.x*xAxis.x - from.y*xAxis.y - from.z*xAxis.z,-from.x*yAxis.x - from.y*yAxis.y - from.z*yAxis.z,-from.x*zAxis.x - from.y*zAxis.y - from.z*zAxis.z,1.0);
return result;}
A Useful Addition To TransformationA Useful Addition To Transformation
Wilf LaLonde @2012Comp 4501
95.400295.4002
Blending
Wilf LaLonde @2012Comp 4501
Many Effect Require Blending TechniquesMany Effect Require Blending Techniques
• Blending permits the colors of a texture to be merged with the colors already drawn on the back buffer.
• To use it, must enable it; disable when done.
glEnable (GL_BLEND);glDisable (GL_BLEND);
Wilf LaLonde @2012Comp 4501
Must Specify Which Blending Factors To UseMust Specify Which Blending Factors To Use
result = SourceFactor*S + DestinationFactor*D
S is the input texture (the source)
D is the screen pixel (the destination orwhat’s already there)
15 factors available: can get by with 3 or 4.15 factors available: can get by with 3 or 4.
glBlendFunc (sourceFactor, destinationFactor);
coming up1. Example Factors, 2. Example Blend functions
Wilf LaLonde @2012Comp 4501
What’s The Complete Set of Factors?What’s The Complete Set of Factors?
• GL_ZERO 0• GL_ONE 1• GL_SRC_COLOR S• GF_DST_COLOR D• GL_SRC_ALPHA a from S• GL_DST_ALPHA a from D• GL_ONE_MINUS_SRC_ALPHA 1-a from S• GL_ONE_MINUS_DST_ALPHA 1-a from
D
Wilf LaLonde @2012Comp 4501
Complete Set...Complete Set...
• GL_ONE_MINUS_SRC_COLOR 1-S• GL_ONE_MINUS_DST_COLOR 1-D
• There are a few additional rules (available through extensions)..
Examples coming upExamples coming up
Wilf LaLonde @2012Comp 4501
What the Blending Factors Apply ToWhat the Blending Factors Apply To
result = SourceFactor*S + DestinationFactor*D
S is the input texture (the source)
D is the screen pixel (the destination orwhat’s already there)
glBlendFunc (sourceFactor, destinationFactor);
• Note that result has no alpha in it once it’s combined.
• Combination applies to R,G,B components independently (each ranges from 0 to 1)…
Wilf LaLonde @2012Comp 4501
Useful Combination 1: BrighteningUseful Combination 1: Brightening
• Take a little from each AND ignore transparency.glBlendFunc (GL_ONE, GL_ONE);
• Consequences:
Result = 1*S + 1*D (clamped to 1 if > 1)
glBlendFunc (sourceFactor, destinationFactor)glBlendFunc (sourceFactor, destinationFactor)
Creates a brightening (whitening) effect…
1 * 0.5 (gray) + 1 * 0.5 (gray) => 1 (white)
Creates a brightening (whitening) effect…
1 * 0.5 (gray) + 1 * 0.5 (gray) => 1 (white)
Wilf LaLonde @2012Comp 4501
Useful Combination 2: Raw TransparencyUseful Combination 2: Raw Transparency
• Use transparency (called alpha blending)glBlendFunc
(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
• Result = a*S + (1- a)*D (clamped to 1 if > 1)
where a is the alpha in the textured color
glBlendFunc (sourceFactor, destinationFactor)glBlendFunc (sourceFactor, destinationFactor)
If a = 0.7 (mostly opaque), get .7S+.3DIf a = 0.7 (mostly opaque), get .7S+.3D
Wilf LaLonde @2012Comp 4501
What Combination Is Like Having Blending Off?What Combination Is Like Having Blending Off?
• Same as usingglBlendFunc (GL_ONE, GL_ZER0);
• Result = 1*S + 0*D = S
So pixel behind is overwritten
glBlendFunc (sourceFactor, destinationFactor)glBlendFunc (sourceFactor, destinationFactor)
Better to say, glDisable (GL_BLEND) instead.Better to say, glDisable (GL_BLEND) instead.
Wilf LaLonde @2012Comp 4501
• One that multiplies rather than adds so that white (1) * what is there => stays the samegray (.5) * what is there => goes darkerblack (0) * what is there => black
glEnable (GL_BLEND);glBlendFunc (GL_ZERO, GL_SRC_COLOR);
• Consequences:
Result = 0*S + S*D (clamped to 1 if > 1)
Useful Combination 3: DarkeningUseful Combination 3: Darkening
This simulates MULTIPLY 0.8*0.8=0.64 (darkens)This simulates MULTIPLY 0.8*0.8=0.64 (darkens)
Wilf LaLonde @2012Comp 4501
95.400295.4002
The OpenGL Stack
Wilf LaLonde @2012Comp 4501
Summary: Thinking With the Left To Right ConventionSummary: Thinking With the Left To Right Convention
How to use the stack? NEXTHow to use the stack? NEXT
v * ABC
MATH works from left to right
CBA
growth direction
From most local to most global
The OpenGL Stack works from right to left
So push C; mult B; mult A; pop
Wilf LaLonde @2012Comp 4501
How Do I Put Something On The StackHow Do I Put Something On The Stack
• Want to translate by T = [tx, ty, tz], and scale by S = [sx, sy, sz].
glMatrixMode (GL_MODELVIEW_MATRIX);glPushMatrix ();
glTranslated (tx, ty, tz);glScaled (sx, sy, sz);
glPopMatrix ();
This puts S*T*whateverIsAlreadyThere on the stack (since it works from right to left)
This puts S*T*whateverIsAlreadyThere on the stack (since it works from right to left)
If W transforms a vehicle to a place in the world with camera C, the stack should contain W * C-1
If W transforms a vehicle to a place in the world with camera C, the stack should contain W * C-1
Wilf LaLonde @2012Comp 4501
95.400295.4002
Shaders
Wilf LaLonde @2012Comp 4501
• If a shader uses a texture variable called “birdTexture” via
uniform sampler2D birdTexture
• How does the game engine know what texture to use; e.g.,
texture called “turkey”
Questions YOU Should Have Had In Your MindQuestions YOU Should Have Had In Your Mind
Generally, stuff explained in Shader::example ()
Wilf LaLonde @2012Comp 4501
• Explain how the ambient occlusion demo does all this.
• Relate how this is different in the engine…
How The Explanation Will GoHow The Explanation Will Go
Wilf LaLonde @2012Comp 4501
• A host of routines are used with names that are synonyms…
glCreateProgram versus glCreateProgramObjectARB
glUseProgram versus glUseProgramObjectARB
glUniform1i versus glUniform1iARB
AsideAside
Wilf LaLonde @2012Comp 4501
95.400295.4002
How The Ambient
Occlusion Demo
Connects shaders with
their textures
Wilf LaLonde @2012Comp 4501
//GettingglGenTextures (1, &textureHandle);shaderProgramHandle = glCreateProgram ();
//DeletingglDeleteTextures (1, &textureHandle);glDeleteProgram (shaderProgramHandle);
//UsingglBindTexture (GL_TEXTURE_2D, textureHandle);
or glBindTexture (GL_TEXTURE_RECTANGLE, textureHandle);glUseProgram (shaderProgramHandle);
Everything done via handlesEverything done via handles
For coordinates in range 0..799
0 means “don’t use a shader”
Wilf LaLonde @2012Comp 4501
//Uploading textures (MESSY)
• glBindTexture (GL_TEXTURE_2D, textureHandle);
• Supply a host of sampling information; e.g. GL_CLAMP versus GL_REPEAT
• Upload the bits to the card… viaglTexImage2D or gluBuild2DMipmaps
Everything done via handlesEverything done via handles
AO Demo has no bits to upload, only game engine which also provides a Texture object to do it all.
Wilf LaLonde @2012Comp 4501
//Uploading shaders (MESSY)
• Compile vertex shader, compile pixel shader.
• shaderProgramHandle = glCreateProgram ();
• Attach the shaders to the program.
• Link the program
Everything done via handlesEverything done via handles
AO Demo provides their code for doing this; game engine provides a Shader object for doing this.
Wilf LaLonde @2012Comp 4501
//Connecting shader samplers to textures
In shader “lesterLightingDiffuse” uniform sampler2D texture;
After creating the shader (do this once)glUseProgram (shaderProgramHandle);glUniform1i ("texture", 0); //a texture unit
When you want to draw with a shaderglUseProgram (shaderProgramHandle);
glActiveTexture (GL_TEXTURE0);glBindTexture (GL_TEXTURE_2D, textureHandle);
ORglBindTexture (GL_TEXTURE_RECTANGLE,
textureHandle);
What You Wanted To KnowWhat You Wanted To Know
0, 1, 2, 3, …
For coordinates in range 0..799
Wilf LaLonde @2012Comp 4501
• Create via handles
glGenFramebuffers (howMany, frameBufs);Plus code to create z-buffer and textures to draw into and code to attach to frame buffer
•Delete via handles
glDeleteFramebuffers (howMany, frameBufs);
•Activate via handles
glBindFramebuffer (GL_FRAMEBUFFER, frameBufs[i]);OR
glBindFramebuffer (GL_FRAMEBUFFER, 0);
FrameBuffers Are The SAMEFrameBuffers Are The SAME
This means now draw into backbuffer
Only AO used frame buffers
Wilf LaLonde @2012Comp 4501
95.400295.4002
How The Engine
Differs From The AO Demo
Wilf LaLonde @2012Comp 4501
• Has texture and shader objects do some work.• Texture provides
test = Texture::read (“turkey”)//Creates handle + path, reads it
texture->load (mipmapping, forceClamp)//Defaults to true, false (to upload onto
card)
activate ()//To bind to the correct texture handle
• Shader provides
activate ()//To bind to the correct program handle
The EngineThe Engine
Wilf LaLonde @2012Comp 4501
• Shaders are a recent introduction that were meant to be specified in level file “castle4.wrl”. The start of the file contain the list of shaders used
Shaders: 0; //currentlyShader 1 nameShader 2 name …
• A shader manager keeps track of the shaders which it associates with an object and the terrain via a shader index… Each object including the terrain has a property
"shader" => "-1“ //-1 means no shader
Some Things That Can Cause ProblemsSome Things That Can Cause Problems
Wilf LaLonde @2012Comp 4501
• It creates a default shader viadefaultShaderIndex = addShader ("lesterlightingDiffuse");
• When a object is imported, it executes
if (shaderIndex == -1) shaderIndex = defaultShaderIndex;
• When the terrain is imported, it executes //if (shaderIndex == -1) shaderIndex = defaultShaderIndex;
When the Shader Manager is SetupWhen the Shader Manager is Setup
Please UNCOMMENT THIS LINE
Wilf LaLonde @2012Comp 4501
• When drawing an object (the castle) or the terrain, it
activates the shader to useactivates the texture to use
• But it fails to executeglActiveTexture (GL_TEXTURE0);
BECAUSE IT DOES THIS ONCE WHEN OPENGL IS SET UP AND ASSUMES IT’S STILL TRUE…
The AO Demo code switches all over the place…
How Else Does It WorkHow Else Does It Work
Wilf LaLonde @2012Comp 4501
• What strategy did I use?• Create one file “ssao.cpp” containing all the
ambient occlusion code and comment out stuff not needed.
• Add it to the “physicsForStudent” project including the AO shaders.
• Find a spot in “game.cpp” to call “WilfDisplay”.
• Find a spot in “ssao.cpp” to invoke “world->draw ()”
• Find a spot in “ssao.cpp” to blend AO with what game engine already drew…
Making Ambient Occlusion Work With The EngineMaking Ambient Occlusion Work With The Engine
BASIC IDEA: AVOID CHANGING ANYTHING BEFORE IT WORKS.
Wilf LaLonde @2012Comp 4501
• Create one file “ssao.cpp” containing the contents of the ambient occlusion file “main.cpp”, “wilfMain.cpp”, and the routines that compile the shader. Add to project.
• Copied over the ambient occlusion shaders into a subdirectory of shaders and called it “AOshaders”.Changes lines from old locations to new
“./src/shaders/ortho.vert” //OLD“../shaders/aoshaders/ortho.vert” //NEW
• Edited each shader so that the first line was#version 120
More Detail StepsMore Detail Steps
Wilf LaLonde @2012Comp 4501
• Fixed the "glew" problem by uncommenting "#include glew.h", commenting out 2 redeclaration error messages, and moving "glewInit" to spot after call to "setupOpenGL ()".
• Much later, I found out that I would crash in routine glBindFragDataLocation (how ssao routine binds a texture to a texture unit) but that it would work if I added EXT to the routine… INSTEAD, added the following after "#include glew.h",
#undef glBindFragDataLocation
#define glBindFragDataLocation glBindFragDataLocationEXT
Making Ambient Occlusion Work With The EngineMaking Ambient Occlusion Work With The Engine
Wilf LaLonde @2012Comp 4501
• There were 3 places in ssao.cpp file that draws quads. Not all of them were drawing counterclockwise (it matters because face culling now has to be on)…
Making Ambient Occlusion Work With The EngineMaking Ambient Occlusion Work With The Engine
glBegin(GL_QUADS);//glVertex2d(0, 0);//glVertex2d(0, size);//glVertex2d(size, size);//glVertex2d(size, 0);glVertex2d (0, 0); //WILF: COUNTER-CLOCKWISE SO ALWAYS WORKS.glVertex2d (size, 0);glVertex2d (size, size);glVertex2d (0, size);
glEnd();
Wilf LaLonde @2012Comp 4501
• Added 2 routines “setupAmbientOcclusion ()” and “wrapupAmbientOcclusion ()” to contain the setup/wrapup code in the ssao.cpp file and called them at the end of “Game::setup ()” and “Game::wrapup ()”
• Also added the following at the end of setupAmbientOcclusion and WilfDisplay…
• Add the following after call to Render2GBuffer.
Making Ambient Occlusion Work With The EngineMaking Ambient Occlusion Work With The Engine
glBindFramebuffer(GL_FRAMEBUFFER, 0);|glActiveTexture(GL_TEXTURE0);glColor4d (1.0, 1.0, 1.0, 1.0);glUseProgram (0); glDisable (GL_TEXTURE_RECTANGLE);
glEnable (GL_TEXTURE_RECTANGLE);
Used to be permanently
enabled (wrecking normal draws)
Wilf LaLonde @2012Comp 4501
• Made resolution, near, far, FOV same for both…
Making Ambient Occlusion Work With The EngineMaking Ambient Occlusion Work With The Engine
//glutInitWindowSize (800, 600);glutInitWindowSize (800, 800); //WILF$$ MAKE THE SAME AS AO SHADER
In game engine (main.cpp)
const float zNear = 1.0; //0.1f; //WILF$$ MAKE NEAR AND FAR THE SAME AS ssao.cpp
const float zFar = 2000; //1000.0f; //WILF$$ MAKE NEAR AND FAR THE SAME AS ssao.cpp
const float fov = 40; //65.238f; //WILF$$ MAKE THE SAME AS ENGINE...
In ssao.cpp
Wilf LaLonde @2012Comp 4501
Making Ambient Occlusion Work With The EngineMaking Ambient Occlusion Work With The Engine
//glGetFloatv(GL_MODELVIEW_MATRIX, mVMat); CopyMemory (mVMat, &camera->inverseCameraMatrix.m11,
sizeof (Transformation));
In ssao.cpp (replaced code that was grabbing the model view matrix mVMatfrom the stack by code that gets it from the existing camera objects).
//M3DInvertMatrix44f(mVMat, iMVMat); CopyMemory (iMVMat, &camera->cameraMatrix.m11,
sizeof (Transformation));
Similarly, code that compute the inverse is obtained from the camera
THIS IS AN INVERSE
Wilf LaLonde @2012Comp 4501
• Assuming the engine draws the world and the ambient occlusion code draws the world, what’s the difference?
The engine wants to draws with the "lesterlightingDiffuse“ shader…
The ssao.cpp code draws with a bunch of different ambient occlusion shaders…
The Most Important Thing To UnderstandThe Most Important Thing To Understand
HOW DO WE MAKE THAT WORK?
Wilf LaLonde @2012Comp 4501
bool disableShaders = false;
void Shader::activate () {extern bool disableShaders; if (disableShaders) return;if (isBroken) {deactivate (); return;}glUseProgramObjectARB (privateProgramHandle);
}
void Shader::deactivate () {extern bool disableShaders; if (disableShaders) return;glUseProgramObjectARB (0);
}
Controlling The GameControlling The Game
Added a global just before void Game::draw () {…}
Changed the routines that activate/deactivate shaders…
Wilf LaLonde @2012Comp 4501
bool disableShaders = false;#define DISABLE disableShaders = true;#define ENABLE disableShaders = false;bool activateAmbientOcclusionBlending = false;
void Game::draw () {//If there is no world, draw a teapot; otherwise, draw the world...//Neither the input manager nor the camera draws itself...enum Choice {AOOnly, NormalOnly, AOThenNormal, NormalThenAO}; Choice choice = NormalThenAO;camera->beginCamera ();
if (world == NULL) { drawTeapots ();
} else {//REVISED PART
}player->draw ();
camera->endCamera ();drawFrameRate ();drawHelp ();
}
REVISED GAME DRAWINGREVISED GAME DRAWING
Wilf LaLonde @2012Comp 4501
activateAmbientOcclusionBlending = choice == NormalThenAO;switch (choice) {
case AOOnly: void WilfDisplay (); DISABLE; WilfDisplay (); break;case NormalOnly: ENABLE; world->draw (); break;case AOThenNormal: DISABLE; WilfDisplay (); ENABLE; world->draw (); break;case NormalThenAO: ENABLE; world->draw (); drawTeapots (); DISABLE; WilfDisplay (); break;
}
REVISED GAME DRAWINGREVISED GAME DRAWING
#define DISABLE disableShaders = true;
#define ENABLE disableShaders = false;
Wilf LaLonde @2012Comp 4501
void DrawModel () {//Used to draw sponza or sibenik models here…//Game engine needs to draw with texture unit 0…glActiveTexture (GL_TEXTURE0); game->world->draw ();
}
void Render2GBuffer () { ….DrawModel();
….}
REVISED ssao.cpp DRAWINGREVISED ssao.cpp DRAWING
Wilf LaLonde @2012Comp 4501
• Recall: ssao.cpp makes and uses frame buffers to draw with…
• Frame buffers draw into textures. So you never see what they draw on the screen…
• Ultimately, though, it must draw into a back buffer…
• What controls that…
BLENDING AO WITH GAMEBLENDING AO WITH GAME
Wilf LaLonde @2012Comp 4501
void RenderAO (int size, int index) {…extern bool activateAmbientOcclusionBlending;if (size < RESOLUTION) {
glBindFramebuffer(GL_FRAMEBUFFER, frameBufs[index]);glDrawBuffer(GL_COLOR_ATTACHMENT2);
} else {glBindFramebuffer (GL_FRAMEBUFFER, 0);
if (activateAmbientOcclusionBlending) {glEnable (GL_BLEND); glBlendFunc (GL_DST_COLOR,
GL_ZERO); }
}
CODE (NOT SHOWN) TO DRAW ONE QUAD…
if (activateAmbientOcclusionBlending) {glDisable (GL_BLEND); }if (size < RESOLUTION && USE_EXTRA_UPSAMPLING_BLUR) Blur (size,
index);}
What Was The Last Thing Drawn By SSAO.cppWhat Was The Last Thing Drawn By SSAO.cppRUNS IN A LOOP WITH size going from small up to RESOLUTION
LAST ITERATION, size is RESOLUTION
Wilf LaLonde @2012Comp 4501
• I did observe a glitch which I assumed was due to the temporal coherence feature. When I rotated continuously, I would sometimes see a dark triangle appear.
• Hacked the code in the shader not to do it...
A GlitchA Glitch
float temporallyBlendedOcclusion (float occlusion) {
return occlusion; //Disabling hack...
return useTemporalSmoothing? occlusion //temporalBlend (...): occlusion;
}
Wilf LaLonde @2012Comp 4501
• Since shader “geometry.frag” is computing the normal in camera space and face culling is on, only faces that face the camera will draw... So the normal MUST be pointing in the +z direction...
• If it’s not, make it so...
Found a Fix for the ATI DFDY Instruction BugFound a Fix for the ATI DFDY Instruction Bug
Shader “geometry.frag#version 120#extensionGL_ARB_texture_rectangle : require
in vec4 pos; out vec4 Pos; out vec4 Norm;
void main() {Pos = pos / pos.w;vec3 n = cross (dFdx (pos.xyz), dFdy (pos.xyz));if (n.z < 0.0) n = -n; //If differentials have a bug, fix it..
Norm = vec4 (normalize(n), sign (abs (pos.z)));}
Wilf LaLonde @2012Comp 4501
• This should convince you that it’s doable…
• Did not try the shadow algorithm… So don’t know if anything is tricky…
ConclusionConclusion