Featured Posts

8. Bump Mapping in GLSL8. Bump Mapping in GLSL Introduction Bump mapping is essential in todays computer games, and computer graphics in general. Would you like to know the best thing about it? It is extremely simple to implement. Bump mapping works...

Read more

Swiftless GLSL Shader DeveloperSwiftless GLSL Shader Developer Swiftless GLSL Shader Developer   Version 0.1a Currently Swiftless GLSL Shader Developer is in it's first public release, and is currently in alpha status, meaning it is not complete and may contain...

Read more

Wordpress Optimization Wordpress Website Optimizations Introduction Wordpress itself is a fairly wonderful tool. Since switching to it, I find it is a lot quicker to make changes to my website and it is also quicker to get...

Read more

36. OpenGL Framebuffers36. OpenGL Framebuffers Introduction Frame buffers are one of those mythical things that we have all heard of, but many beginner OpenGL developers avoid because there is not much information about them, and they can be confusing...

Read more

1. Terrain Class1. Terrain Class Terrain is one of those things that so far, hasn't been perfectly recreated in computer graphics. But it is almost there! Looking over a beautiful landscape can be one of the most amazing feelings in the...

Read more

  • Prev
  • Next

2. OpenGL 4 Shaders

Posted on : 08-08-2010 | By : Swiftless | In : OpenGL 4

Tags: , , , , , , ,

0

Introduction

Because OpenGL 3.x and up is extremely shader oriented, I am going to show you how to integrate our shader code from the GLSL section of the website. I am not going to go into GLSL details here, as I have done that, and will continue to do that in the GLSL portion of the site. This tutorial is a quick guide on how to get shaders working in our current framework. So why don’t we get to it, so we can move on to using matrices in the new OpenGL pipeline. Keep in mind that I am only working with Vertex and Fragment shaders still, I will introduce Geometry shaders in a later tutorial.

Coding

The code for this tutorial is going to be fairly minimal, and I may have updates to the shader.cpp and shader.h files that are in the GLSL portion of the site. If you have any queries, feel free to ask.
The first thing we are going to do, is copy our shader.h and shader.cpp files from the GLSL section of the site, and add them into our new Visual Studio project. Then go ahead and open opengl_3.h.

Opengl_3.h

Inside of opengl_3.h where we have our opengl context class structure, jump up the top and make sure you include the shader.h file into your source code.

#include "shader.h"

Once we have done this, go down into our private variables for our context class, and add an instance of a shader variable. If you are working with several shaders, you can make this into an array, or create separate shader variables. Personally I would create an array of shaders.

class OpenGLContext {
...
private:
int windowWidth; // Store the width of our window
int windowHeight; // Store the height of our window

Shader *shader; // Our GLSL shader
...
};

Opengl_3.cpp

Once we have a shader variable declared that we can play with, open up opengl_3.cpp and jump down to the setupScene method. Inside of here we are going to set our shader to a new shader object, based on shader.vert and shader.frag. Both of which are included in the project.

void OpenGLContext::setupScene(void) {
glClearColor(0.4f, 0.6f, 0.9f, 0.0f); // Set the clear color based on Microsofts CornflowerBlue (default in XNA)

shader = new Shader("shader.vert", "shader.frag"); // Create our shader by loading our vertex and fragment shader
}

And then all we have left to do is jump to our renderScene method and bind and unbind our shader as required. You will notice that we don’t have any geometry to draw yet, so you won’t see anything yet, but don’t worry, we are getting there :)

void OpenGLContext::renderScene(void) {
glViewport(0, 0, windowWidth, windowHeight); // Set the viewport size to fill the window
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Clear required buffers

shader->bind(); // Bind our shader

shader->unbind(); // Unbind our shader

SwapBuffers(hdc); // Swap buffers so we can see our rendering
}

Shader.cpp

I mentioned at the start that these are pretty much the same shader.cpp and shader.h files that are in the GLSL section of the website. Here I am going to list one major change that I have made. I am binding two variables to our shader. These variables are constants and are called in_Position and in_Color and will be used to send positions and colors to our shader without binding and unbinding them every frame. These lines are added in our init method for our shader:

void Shader::init(const char *vsFile, const char *fsFile) {
...
glBindAttribLocation(shader_id, 0, "in_Position"); // Bind a constant attribute location for positions of vertices
glBindAttribLocation(shader_id, 1, "in_Color"); // Bind another constant attribute location, this time for color
...
}

Shader.vert

Because this tutorial has been so short, I am going to give a quick talk about the changes done to vertex and fragment shaders in GLSL 1.50. To declare which version of GLSL you are using, you can use a line similar to the following, which sets our GLSL version to 1.50:

#version 150 core

This can be changed for any valid version of GLSL. In GLSL 1.50, we no longer have gl_ModelViewMatrix, gl_ProjectionMatrix, gl_Vertex, etc, etc. Because we now have to manage and send all of this information to the shaders ourselves. In the next tutorial I will introduce self manipulated model, view and projection matrices, but for now I will stick with the basics. Because I created the two variables in_Position and in_Color to bind to our shader, we have to create these. They will both be vec3 variables, and because we are using GLSL 1.5, we also need to declare if the variable is going “in” or “out” of the current shader. There are no more uniform or varying variables to deal with. I am also going to create one “out” variable called pass_Color which is also a vec3 variable. This will send any outgoing color from the vertex shader to the fragment shader. Luckily setting the final position requires some similar code, which is setting the gl_Position variable.

#version 150 core
in vec3 in_Position;

in vec3 in_Color;
out vec3 pass_Color;
void main(void)

{

gl_Position = vec4(in_Position, 1.0);

pass_Color = in_Color;

}

Shader.frag

In our fragment shader, we are also going to declare the version of GLSL that we are working with and because we had an “out” variable in our shader.vert file, then we need an “in” variable of the same name in our fragment shader. So we are going to create an “in” variable, of type vec3 called pass_Color. Now fragment shaders no longer have gl_FragColor, instead we need to manually declare an “out” variable of type vec4, which will give our color to our GPU. I am going to call this “out” variable out_Color and I am going to set it to the pass_Color, which is the variable we sent in to our shader.

#version 150 core
in vec3 pass_Color;
out vec4 out_Color;
void main(void)

{

out_Color = vec4(pass_Color, 1.0);

}

If all went well, you should now be set up to use shaders in your application and your application should run without any errors. Stick with me for the next two tutorials, and by the end of the fourth tutorial, we will now be rendering things to the screen. OpenGL 3.x and 4.x takes a bit more preparation, but it does make a difference in the end, especially when it comes to speed as without the immediate mode, our rendering should be extremely more efficient.

Downloads

Visual Studio 2010 Project
PDF version

If you have any questions you can comment below or email me at swiftless@gmail.com

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.0/10 (2 votes cast)
VN:F [1.9.3_1094]
Rating: +2 (from 2 votes)

1. OpenGL 4 Window

Posted on : 03-08-2010 | By : Swiftless | In : OpenGL 4

Tags: , , , , , ,

4

Introduction

OpenGL has undergone some major changes recently from version 3 and onwards. OpenGL 3 introduced a new way of programming in OpenGL that slightly raises the learning curve, but also does away with the entire Immediate Mode by deprecating a lot of the functions. Now I know I have called this part of the site “OpenGL 4 Tutorials”, and all of a sudden I am talking about OpenGL 3, this is because OpenGL 3 and OpenGL 4 are extremely similar, with OpenGL 4 bringing in some new extensions, and because my graphics card only supports OpenGL 3.x. If you would like to see some OpenGL 4 extensions in use, you can always donate and help me get a new graphics card. In this tutorial, I am going to be simply creating a window with an OpenGL 3.2 context attached, nothing more, nothing less. These tutorials are going to be for Windows only, but if you are keen to get them working on a different OS (My Macbook doesn’t support OpenGL 3.x), please send me the ports and I will post them up.

OpenGL 3+ Key Differences

An OpenGL 3+ and 4 context requires you to create a standard OpenGL context (version 1.x or 2.x) and then get your application to opt-in to using an OpenGL 4 context.
Without the Immediate Mode, OpenGL has gone for an almost entirely shader driven architecture, which gives us control over everything from the word go, and also greatly improves performance.
When it comes to rendering shapes, instead of setting the state and then calling the vertices one by one, OpenGL 3 and upwards wants us to use Vertex Buffer Objects and Vertex Buffer Arrays straight out. Vertex Buffer Objects were available in OpenGL 1.5 and up as an extension, but they are now a part of the core of OpenGL.
Matrices are one of the major things affected by OpenGL 3. To put it simply, OpenGL does no matrix operations for us such as setting the Projection Matrix, setting the Model Matrix and setting the View Matrix. This means calls such as glRotate and glTranslate are not deprecated and not recommended. OpenGL now likes us to handle our own matrices. I will talk about this in a later tutorial, but there is a library called GLM, designed for use with OpenGL and GLSL, which will help us with our matrix operations.

Coding

*note* You can jump straight to the bottom of this page to grab the PDF version of this tutorial, or the project files. *note*
Let’s finally get into this tutorial, because it is going to be a long one. I’m also going to be aiming for a more Object Oriented approach to programming in these newer tutorials.
This tutorial is going to be very similar in some ways to most Win32 OpenGL tutorials available, the only difference being that it has an OpenGL 3.2 context instead of a standard context. So open up Visual Studio and create a new Windows Console Application in C++. Make sure it is empty to begin with, and then create 4 files. I am calling them: “main.cpp, main.h, opengl_3.cpp, opengl_3.h”. I am going to go through these files one by one, starting with the header files, so that we don’t get mixed up shuffling between them.

Main.h

Main.h is going to contain all of our header files for the time being. So open it up and paste the following code. I won’t explain it, as it is pretty straight forward; we are including some header files and linking some libraries, the only tricky part may be “#pragma once”, which isn’t standard but is widely supported, and means to only include the file once during compilation.

#pragma once

// Include Windows functions
#include

// Include input and output operations
#include

// OpenGL and GLEW Header Files and Libraries
#include
#include
#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "opengl32.lib")

As you can see from the above code, we are once again using GLEW. GLEW is up to date with the latest OpenGL 3.x and possibly 4.0 extensions. I highly recommend the use of it as it makes coding in OpenGL so much easier without having to worry about declaring extensions by yourself.

Opengl_3.h

The first thing we want to include here is our main.h file. So add the line:

#include "main.h"

Once we have included our main header file which contains access to the GLEW and OpenGL commands, we are going to want to create a new class. I am going to call this class OpenGLContext and it is going to be responsible for creating a context, handling setting up of our scene, resizing of our scene, rendering of our scene, and finally, cleaning up of our scene. Start off with an empty class like so:

/**
OpenGLContext is a class designed to store all of your OpenGL functions and keep them
out of the way of your application logic. Here we have the ability to create an OpenGL
context on a given window and then render to that window.
*/
class OpenGLContext {
public:

private:

protected:
};

Next up, we are going to come up with some protected variables that will keep track of our window. When working with the Win32 API, each Window you see has its own HWND which is the identifier for that window. We also have two different contexts we need to work with, the first is the HDC, which is the device context, and the second is the HGLRC which is an OpenGL rendering context. If we create a variable to handle each of these, we get:

class OpenGLContext {
...

protected:
HGLRC hrc; // Rendering context
HDC hdc; // Device context
HWND hwnd; // Window identifier
};

Once we have the information we need for a window and a context, we need to keep track of the width and the height of our window. If we don’t keep track of these, then whenever we resize the window, we will find that parts of it are not rendered to, or we render more than we have to, resulting in some of our image being cut off. We are going to add two private variables to keep track of this for us:

class OpenGLContext {
...

private:
int windowWidth; // Store the width of our window
int windowHeight; // Store the height of our window

...
};

Finally we need to come up with some method stubs for controlling our OpenGLContext object. I am going to work with two different constructors and a destructor for some standard methods. Followed by four other methods for working with our context which are going to be called “create30Context(HWND), setupScene(void), reshapeWindow(int, int), renderScene(void)”.

class OpenGLContext {
public:
OpenGLContext(void); // Default constructor
OpenGLContext(HWND hwnd); // Constructor for creating our context given a hwnd
~OpenGLContext(void); // Destructor for cleaning up our application
bool create30Context(HWND hwnd); // Creation of our OpenGL 3.x context
void setupScene(void); // All scene information can be setup here
void reshapeWindow(int w, int h); // Method to get our window width and height on resize
void renderScene(void); // Render scene (display method from previous OpenGL tutorials)

...
};

This is all we are going to need for our opengl_3.h header file for now. So let’s go and start on opengl_3.cpp.

Opengl_3.cpp

To give use access to our class methods, you are going to want to include opengl_3.h of course, so that will be line number one for this file.

#include "opengl_3.h"

Now let’s get to building us some methods for our class. I am going to start off with the two constructors and the destructor. Our first constructor, the default one, at the moment does nothing, so you can just create an empty constructor. But the second one will make a call to our create30Context method.

/**
Default constructor for the OpenGLContext class. At this stage it does nothing
but you can put anything you want here.
*/
OpenGLContext::OpenGLContext(void) {

}

/**
Constructor for the OpenGLContext class which will create a context given a windows HWND.
*/
OpenGLContext::OpenGLContext(HWND hwnd) {
create30Context(hwnd); // Create a context given a HWND
}

When we get to our destructor, it will handle the removal of our rendering context and our device context. For this, we make use of wglMakeCurrent, wglDeleteContext and ReleaseDC.

/**
Destructor for our OpenGLContext class which will clean up our rendering context
and release the device context from the current window.
*/
OpenGLContext::~OpenGLContext(void) {
wglMakeCurrent(hdc, 0); // Remove the rendering context from our device context
wglDeleteContext(hrc); // Delete our rendering context

ReleaseDC(hwnd, hdc); // Release the device context from our window
}

Let’s get onto our create30Context method now. This method will take in a HWND value to identify a window, and will create a valid rendering and device context on top of it. Create an empty method for this, and then we will set the HWND for our object, and get a valid HDC. I’ve made this method a Boolean value, so we can return a false value if we are unable to successfully create a context of any kind. However by default, we will fall back to and OpenGL 2.1 context if unable to create an OpenGL 3.x context.

/**
create30Context creates an OpenGL context and attaches it to the window provided by
the HWND. This method currently creates an OpenGL 3.2 context by default, but will default
to an OpenGL 2.1 capable context if the OpenGL 3.2 context cannot be created.
*/
bool OpenGLContext::create30Context(HWND hwnd) {
this->hwnd = hwnd; // Set the HWND for our window

hdc = GetDC(hwnd); // Get the device context for our window

return true; // We have successfully created a context, return true
}

The next thing we need to do, is create a variable called a PIXELFORMATDESCRIPTOR which determines how many bits of colour and depth we get, along with giving us double buffering and support for OpenGL. To do this, we first need to create a new variable, I am going to call it pfd and then we need to allocate some empty memory for it. Here, 32 bits of colour, gives us R, G, B and A channels, while 24 bits gives us only R, G and B (each channel takes 8 bits). After we have set aside some memory for this variable, we need to set the size of it, which will always be sizeof(PIXELFORMATDESCRIPTOR). Next, we will set the flags which allow double buffering, opengl support and drawing to a window. Next up, we set the iPixelType to allow RGBA pixels, before we set how many bits we want in our color and depth buffers. Finally, we need to set the iLayerType. We are going to set this to the Main_Plane for our window.

bool OpenGLContext::create30Context(HWND hwnd) {
this->hwnd = hwnd; // Set the HWND for our window

hdc = GetDC(hwnd); // Get the device context for our window

PIXELFORMATDESCRIPTOR pfd; // Create a new PIXELFORMATDESCRIPTOR (PFD)
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); // Clear our  PFD
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); // Set the size of the PFD to the size of the class
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; // Enable double buffering, opengl support and drawing to a window
pfd.iPixelType = PFD_TYPE_RGBA; // Set our application to use RGBA pixels
pfd.cColorBits = 32; // Give us 32 bits of color information (the higher, the more colors)
pfd.cDepthBits = 32; // Give us 32 bits of depth information (the higher, the more depth levels)
pfd.iLayerType = PFD_MAIN_PLANE; // Set the layer of the PFD

return true; // We have successfully created a context, return true
}

Next up, we need to choose a pixel format for our device context, based on our pixel format descriptor. To do this, we make a call to ChoosePixelFormat and pass through our hdc and pfd variables, in return we get an integer value that represents our pixel format, which we can then use to set our pixel format for our device context using SetPixelFormat as seen below.

bool OpenGLContext::create30Context(HWND hwnd) {
this->hwnd = hwnd; // Set the HWND for our window

hdc = GetDC(hwnd); // Get the device context for our window

...

int nPixelFormat = ChoosePixelFormat(hdc, &pfd); // Check if our PFD is valid and get a pixel format back
if (nPixelFormat == 0) // If it fails
return false;

bool bResult = SetPixelFormat(hdc, nPixelFormat, &pfd); // Try and set the pixel format based on our PFD
if (!bResult) // If it fails
return false;

return true; // We have successfully created a context, return true
}

Once we have our pixel format all set up. We need to go ahead and create our OpenGL context. To do this, we need to first create an OpenGL 2.1 compatible context, and then call a new OpenGL 3.x extension called wglCreateContextAttribsARB to create an OpenGL 3.x compatible context. So let’s create our OpenGL 2.1 context as per a standard Win32 OpenGL application.

HGLRC tempOpenGLContext = wglCreateContext(hdc); // Create an OpenGL 2.1 context for our device context
wglMakeCurrent(hdc, tempOpenGLContext); // Make the OpenGL 2.1 context current and active

And now we will go ahead and enable GLEW so that we can use our new OpenGL 3.x context creation extension.
GLenum error = glewInit(); // Enable GLEW
if (error != GLEW_OK) // If GLEW fails
return false;

To create our context correctly, we need to set some attributes. These include the major and minor version of the OpenGL version we wish to use, followed by a flag to set this as a forward compatible context. When I say major and minor version, OpenGL versions come in this naming convention “major.minor”, so in OpenGL 3.2, the major version is 3 and the minor version is 2. This can be change to give OpenGL 3.2, 3.1, 3.0 or even 4.0 contexts.

int attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3, // Set the MAJOR version of OpenGL to 3
WGL_CONTEXT_MINOR_VERSION_ARB, 2, // Set the MINOR version of OpenGL to 2
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, // Set our OpenGL context to be forward compatible
0
};

Now that our attributes are all sorted out, we are going to do a check to see if our OpenGL 3.x context creation extension is available. If it is, we are going to create our OpenGL 3.2 context, if it isn’t, then we are going to stick with the OpenGL 2.1 context we created above. To switch to the new context after it has been created, we need to make sure that no context is current on our window, and then delete the old context, before finally making our new OpenGl 3.2 context current.

if (wglewIsSupported("WGL_ARB_create_context") == 1) { // If the OpenGL 3.x context creation extension is available
hrc = wglCreateContextAttribsARB(hdc, NULL, attributes); // Create and OpenGL 3.x context based on the given attributes
wglMakeCurrent(NULL, NULL); // Remove the temporary context from being active
wglDeleteContext(tempOpenGLContext); // Delete the temporary OpenGL 2.1 context
wglMakeCurrent(hdc, hrc); // Make our OpenGL 3.0 context current
}
else {
hrc = tempOpenGLContext; // If we didn't have support for OpenGL 3.x and up, use the OpenGL 2.1 context
}

Finally, to check that we have created our context correctly, we are just going to pull out the MAJOR and MINOR version numbers for OpenGL and output them to a console.

int glVersion[2] = {-1, -1}; // Set some default values for the version
glGetIntegerv(GL_MAJOR_VERSION, &glVersion[0]); // Get back the OpenGL MAJOR version we are using
glGetIntegerv(GL_MINOR_VERSION, &glVersion[1]); // Get back the OpenGL MAJOR version we are using

std::cout << "Using OpenGL: " << glVersion[0] << "." << glVersion[1] << std::endl; // Output which version of OpenGL we are using On Windows, you won’t get a console for a Win32 Application, but a nifty trick to get console output, is to open up Command Prompt, navigate to your directory with your executable file, and use something like: “program.exe > temp.txt”

This will run your application, and save all output to the file temp.txt. Linux programmers may already be familiar with calls like this.
Now we still have three more methods we need to create here before we are done, but luckily for us, they are extremely short. The first I will look at is setupScene, which takes no parameters, and will only set up our OpenGL Clear Color value. I am going to set it to the nice CornFlowerBlue you get when working with XNA. I grew fond of this colour, and it looks nicer than a standard black or white.

/**
setupScene will contain anything we need to setup before we render
*/
void OpenGLContext::setupScene(void) {
glClearColor(0.4f, 0.6f, 0.9f, 0.0f); // Set the clear color based on Microsofts CornflowerBlue (default in XNA)
}

Moving on, we now have our reshapeWindow method. This method will take in two integers, one for the width of our window and the other for the height of our window. It will then set our OpenGLContext objects width and height to these values.

/**
reshapeWindow is called every time our window is resized, and it sets our windowWidth and windowHeight
so that we can set our viewport size.
*/
void OpenGLContext::reshapeWindow(int w, int h) {
windowWidth = w; // Set the window width
windowHeight = h; // Set the window height
}

And the last method for this file, is our renderScene method, which once again takes no arguments. The first thing we need to do, is set the size of our viewport to the size of our window, which is done with a call to glViewport. Next we will clear our color, depth and stencil buffers, before finally swapping our front and back buffers to draw to the screen.

/**
renderScene will contain all our rendering code.

The first thing we are going to do is set our viewport size to fill the entire window.

Next up we are going to clear our COLOR, DEPTH and STENCIL buffers to avoid overlapping
of renders.

Any of your other rendering code will go here.

Finally we are going to swap buffers.
*/
void OpenGLContext::renderScene(void) {
glViewport(0, 0, windowWidth, windowHeight); // Set the viewport size to fill the window
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Clear required buffers
SwapBuffers(hdc); // Swap buffers so we can see our rendering
}

Now we have everything in place for our basic OpenGL 3.2 context, so let’s go and finish off this tutorial with the main.cpp file, which will handle all of our Window creation.

Main.cpp

For the purpose of these tutorials, I am going to assume that we are working with single window applications and am not going to go for a more OO approach to window creation. So let’s get on to creating our window.
The first thing we need to do here is to include our common header files, main.h and opengl_3.h. Followed by declaring some variables. We are going to need an instance of an OpenGLContext object, a boolean value to say as to whether or not we are still running our application and a standard HINSTANCE variable for Win32. We are also going to give a method declaration for WndProc which is also required for a Windows application.

#include "main.h"
#include "opengl_3.h"

OpenGLContext openglContext; // Our OpenGL Context class

bool running = true; // Whether or not the application is currently running

HINSTANCE hInstance; // The HINSTANCE of this application
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Standard window callback

The rest of this tutorial, is made up of three methods. The first one here, is required in any Windows application and is responsible for our windows callbacks. We are going to look for calls to resize the window, and for calls to destroy the window. When we find a call to resize the window, we are going to call our openglContext.reshapeWindow method. Lets take a look at the definition for this method.

/**
WndProc is a standard method used in Win32 programming for handling Window messages. Here we
handle our window resizing and tell our OpenGLContext the new window size.
*/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {

return DefWindowProc(hWnd, message, wParam, lParam);
}

In order to look for different window calls, we turn to the message parameter in the method definition. This is a UINT variable, which can be tied to any of the WM_* variables. We are going to need WM_SIZE for window resizing, and WM_DESTROY for calls to destroy the window. I am going to use a simple switch statement to check for these like so:

switch (message) {
case WM_SIZE: // If our window is resizing
{

}

case WM_DESTROY:
{

}
}

When it comes to our window resizing, we are going to need to update our OpenGL context so that it knows the new size of the window. To do this, we can pull out the width and height of the window using calls to LOWORD(lParam) and HIWORD(lParam), which makes things fairly simple for us. Our method now becomes:

/**
WndProc is a standard method used in Win32 programming for handling Window messages. Here we
handle our window resizing and tell our OpenGLContext the new window size.
*/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_SIZE: // If our window is resizing
{
openglContext.reshapeWindow(LOWORD(lParam), HIWORD(lParam)); // Send the new window size to our OpenGLContext
break;
}

case WM_DESTROY:
{

}
}

return DefWindowProc(hWnd, message, wParam, lParam);
}

The only thing left to check for now, is when a window is destroyed. Then we need to send a call to PostQuitMessage so that we can exit our application.

/**
WndProc is a standard method used in Win32 programming for handling Window messages. Here we
handle our window resizing and tell our OpenGLContext the new window size.
*/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_SIZE: // If our window is resizing
{
openglContext.reshapeWindow(LOWORD(lParam), HIWORD(lParam)); // Send the new window size to our OpenGLContext
break;
}

case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
}

return DefWindowProc(hWnd, message, wParam, lParam);
}

While we now have a method which will handle all of the call backs for our window, we need to actually go ahead and create a window. So I am going to create a new method called createWindow, which will return a boolean value which determines whether or not the window was created successfully. It’s parameters are an LPCWSTR for the title of the window, and two integers, one for the width and one for the height of the window.

bool createWindow(LPCWSTR title, int width, int height) {

return true;
}

Once we have our method skeleton in place, we need to setup some variables for our window. We will need a WNDCLASS, HWND and a DWORD. The WNDCLASS, which I will call windowClass sets all the basic information for a window, such as the icon, cursor, type of redraw, the instance of the owner application, etc. The HWND variable which I will just call hwnd, will hold the unique identifier for the window which we create, and finally the DWORD variable, which I am going to call dwExStyle and that just sets the type of window and that it has an edge.
I’m not going to go into detail about all the settings for this, as it’s not an OpenGL topic, its a Win32 topic, so here’s just the code. I have included a quick error check to make sure the windowClass variable can be registered:

bool createWindow(LPCWSTR title, int width, int height) {
WNDCLASS windowClass;
HWND hWnd;
DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;

hInstance = GetModuleHandle(NULL);

windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
windowClass.lpfnWndProc = (WNDPROC) WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = LoadIcon(NULL, IDI_WINLOGO);
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = NULL;
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = title;

if (!RegisterClass(&windowClass)) {
return false;
}

return true;
}

Next up, we are going to create our window using the above window class, and then we are going to create our OpenGL context on the window before showing the window and making a quick call to update it.

bool createWindow(LPCWSTR title, int width, int height) {
...

hWnd = CreateWindowEx(dwExStyle, title, title, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, width, height, NULL, NULL, hInstance, NULL);

openglContext.create30Context(hWnd); // Create our OpenGL context on the given window we just created

ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);

return true;
}

This should now give us a window, with an OpenGL 3 context, and it should also be visible. The last thing we need to do is create a WinMain method which will be used to launch our application. Lets create an empty WinMain method, and then we will go ahead and fill this in. Note that I have left in the MSG variable called msg, just because we use it for our return value.

int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR    lpCmdLine,
int       nCmdShow) {
MSG msg;

return (int) msg.wParam;
}

Before we fill this in, I am going to give a brief rundown of what to expect. The first few lines are going to be used to convert the title of the window from a char array to an LPCWSTR, they are just an annoying necessity because the CreateWindowEx method doesn’t support char arrays. The next two lines after this will create our window, and setup our OpenGL context, and we will end with a loop that will continue running for as long as the application does, and will be responsible for rendering and checking for window messages. Lets take a look at the first few lines, which convert our char array.

int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR    lpCmdLine,
int       nCmdShow) {
MSG msg;

/**
The following 6 lines of code do conversion between char arrays and LPCWSTR variables
which are used in the Windows API.
*/
char *orig = "OpenGL 3 Project"; // Our windows title
size_t origsize = strlen(orig) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t wcstring[newsize];
mbstowcs_s(&convertedChars, wcstring, origsize, orig, _TRUNCATE);

return (int) msg.wParam;
}

Now let’s make the calls to create our window and setup our OpenGL scene.

int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR    lpCmdLine,
int       nCmdShow) {
...

createWindow(wcstring, 500, 500); // Create our OpenGL window

openglContext.setupScene(); // Setup our OpenGL scene

return (int) msg.wParam;
}

And finally we can set up our infinite loop. We will use the Win32 call to PeekMessage to check for calls to our window. If we get a WM_QUIT message we are going to set our running variable to false. Otherwise we are going to translate and dispatch the message, which is done in our callback. And if we don’t have any messages to process, we are going to call our openglContext.renderScene method before returning.

int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR    lpCmdLine,
int       nCmdShow) {
...

/**
This is our main loop, it continues for as long as running is true
*/
while (running)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // If we have a message to process, process it
if (msg.message == WM_QUIT) {
running = false; // Set running to false if we have a message to quit
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else { // If we don't have a message to process
openglContext.renderScene(); // Render our scene (which also handles swapping of buffers)
}
}

return (int) msg.wParam;
}

And wow, if you made it this far, give yourself a well deserved pat on the back! It took me a few days to write this tutorial, which is an initial setup on top of which all our other tutorials will build, so once you get it down you are ready to move onto the next. I am also providing Visual Studio 2010 projects for these tutorials, and PDF versions for download. For those of you who have been waiting, I’m sorry it has taken so long, but this is now a 13 page, 4,500+ word introduction to setting up an OpenGL compatible context on a window.

Downloads

Visual Studio 2010 Project
PDF version

If you have any questions you can comment below or email me at swiftless@gmail.com

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.3/10 (4 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

8. Bump Mapping in GLSL

Posted on : 24-06-2010 | By : Swiftless | In : GLSL, Tutorials

Tags: , , , , , , , ,

4

Introduction

Bump mapping is essential in todays computer games, and computer graphics in general. Would you like to know the best thing about it? It is extremely simple to implement. Bump mapping works by taking an image which stores surface normals on a per-pixel basis. This means that we can apply standard lighting techniques that require a normal value on a per-pixel basis instead of a per-vertex or per-surface basis. This gives our applications a greatly added sense of realism.

How does bump mapping work in OpenGL with GLSL though? GLSL texturing works on a per-texel basis, where a texel can be thought of as a scaled pixel, either larger or smaller, and we get access to a texel at any fragment on an objects surface when we are texturing in GLSL. We already covered texturing in GLSL in a previous tutorial, so I won’t go over it again.

When you look at a normal map, it is generally a blue and purple color. To get your head around normal mapping, all you need to understand is that each pixel in this image file, can be mapped to a normal value. Once you can understand that, normal mapping is extremely straight forward.

Don’t get this tutorial on bump mapping confused with tangent-space bump mapping though. There aren’t many tutorials around that explain the different, but regular bump mapping only cares about the normal maps relation to lights. Tangent space bump mapping takes it a step further and takes into account the objects surfaces in relation-to the light as well as the normal maps relation.

Coding

Enough theory, how can we get it into OpenGL and GLSL. The first thing we will want to do is load in our normal map, and apply it to our object in OpenGL. This requires multi-texturing in OpenGL, which I don’t believe I have covered in GLSL, so I will include that in this tutorial. This code is going to be based on the GLSL texturing tutorial, but you may notice some additions to make it cross-platform between OSX and Windows correctly.

Main.cpp

We are only going to need one new variable for the main.cpp file which will be used to store our normal map texture. This is stored and used just like a normal texture. I am going to call this normal_texture, and define it with our texture variable at the top of our file.

GLuint normal_texture; // Our normal map texture

Then go down to your init method, and remove the current line that creates a texture, and replace it with the following two lines, which will create both of our new

texture = LoadTexture("colour_map.raw", 256, 256);
normal_texture = LoadTexture("normal_map.raw", 256, 256);

Inside of our init method you may also notice the following code, this is for cross-platform compatibility and simply checks if we are on OSX or not. If not, we initialize glew.

#if ( (defined(__MACH__)) && (defined(__APPLE__)) )
#else
glewInit();
#endif

The rest of our code for the main source code file, goes into our cube method, which I have now modified to draw a square instead.

You should already have code to set the first texture, and we are going to adjust this slightly by adding the following line after we set our active texture:

glEnable(GL_TEXTURE_2D);

Our code to set up our first texture should now look like:

glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
int texture_location = glGetUniformLocation(shader.id(), "color_texture");
glUniform1i(texture_location, 0);
glBindTexture(GL_TEXTURE_2D, texture);

Now we need to set up our second texture. This is done by activating the next texture, GL_TEXTURE1 and modifying the other calls to point to our normal map texture. When we do this, we need to make sure that our glUniform1i for our normal map location in the shader, has the value 1. When multi-texturing in GLSL, each texture used will have an incremented value in the shader. Our final code will look like:

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
int normal_location = glGetUniformLocation(shader.id(), "normal_texture");
glUniform1i(normal_location, 1);
glBindTexture(GL_TEXTURE_2D, normal_texture);

I won’t explain the code for drawing the square, as I have done this in previous tutorials, so I will jump to after our square. We will need to do some cleaning up, as we don’t want our texture states to mess up when we render other objects later on. All I am doing to clean up, is setting the active texture, binding it to nothing, and then disabling texturing on this texture. Note that I am doing this in reverse to how I have set the textures. You can do this in any order, but I like this as I find it easier to follow (count up on initialization, and then count down on de-initialization).

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);

Shader.vert

Our vertex shader requires absolutely no extra calls, so just use the one provided in the previous texturing tutorial.

Shader.frag

Shader.frag is going to contain all of our bump mapping calculations. To get this going, we need to add a new uniform variable, which will load in our normal mapping texture:

uniform sampler2D normal_texture;

Now that we have access to our normal map, lets load it in. For a normal, we only require a 3 value vector, or vec3 in GLSL, and we are going to normalize this to make sure the final normal vector is of unit length. In other words, it has a length of 1.0. But in this line take note of the (* 2.0 – 1.0). When we read in a texture value, we get a number between 0.0 and 1.0 as color cannot have a negative value. This then multiplies the value by 2.0, giving us values between 0.0 and 2.0, and then subtracts 1.0 so we get our final values in the range of -1.0 to 1.0. We have to do this manipulation as a normal vector is 3D and can be pointing in any direction. It’s a nifty little trick which allows us to convert a normal map texture file to a normal map.

// Extract the normal from the normal map
vec3 normal = normalize(texture2D(normal_texture, gl_TexCoord[0].st).rgb * 2.0 - 1.0);

Since we now have the normal value for the current pixel, I am going to set up a quick light, located at the top right of the scene, and also a little towards us. Usually you would base this on actual lights in your scene, and to do so, take a look at my GLSL lighting tutorial.

// Determine where the light is positioned (this can be set however you like)
vec3 light_pos = normalize(vec3(1.0, 1.0, 1.5));

Finally we can get to some familiar code. We are going to calculate the diffuse value for the current pixel, based on our normal extracted from the normal map. Then we are going to multiply the diffuse value against our color texture, and assign the output to our gl_FragColor variable.

// Calculate the lighting diffuse value
float diffuse = max(dot(normal, light_pos), 0.0);

vec3 color = diffuse * texture2D(color_texture, gl_TexCoord[0].st).rgb;

// Set the output color of our current pixel
gl_FragColor = vec4(color, 1.0);

And now you should have a perfectly working bump mapping shader. If you have any questions, feel free to email me at swiftless@gmail.com or leave a comment below.

Downloads

Colour Map Texture
Normal Map Texture

Tutorial Code

Main.cpp

#if ( (defined(__MACH__)) && (defined(__APPLE__)) )
#include <stdlib.h>
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#include <OpenGL/glext.h>
#else
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glext.h>
#endif
#include "shader.h"

Shader shader;

GLuint texture;
GLuint normal_texture; // Our normal map texture

GLuint LoadTexture( const char * filename, int width, int height )
{
GLuint texture;
unsigned char * data;
FILE * file;

//The following code will read in our RAW file
file = fopen( filename, "rb" );

if ( file == NULL ) return 0;
data = (unsigned char *)malloc( width * height * 3 );
fread( data, width * height * 3, 1, file );

fclose( file );

glGenTextures( 1, &texture ); //generate the texture with the loaded data
glBindTexture( GL_TEXTURE_2D, texture ); //bind the texture to it’s array

glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); //set texture environment parameters

//And if you go and use extensions, you can use Anisotropic filtering textures which are of an
//even better quality, but this will do for now.
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

//Here we are setting the parameter to repeat the texture instead of clamping the texture
//to the edge of our shape.
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

//Generate the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

free( data ); //free the texture

return texture; //return whether it was successfull
}

void FreeTexture( GLuint texture )
{
glDeleteTextures( 1, &texture );
}

void init(void) {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);

#if ( (defined(__MACH__)) && (defined(__APPLE__)) )
#else
glewInit();
#endif

shader.init("shader.vert", "shader.frag");

texture = LoadTexture("colour_map.raw", 256, 256);
normal_texture = LoadTexture("normal_map.raw", 256, 256);
}

void cube (void) {
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
int texture_location = glGetUniformLocation(shader.id(), "color_texture");
glUniform1i(texture_location, 0);
glBindTexture(GL_TEXTURE_2D, texture);

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
int normal_location = glGetUniformLocation(shader.id(), "normal_texture");
glUniform1i(normal_location, 1);
glBindTexture(GL_TEXTURE_2D, normal_texture);

glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);

glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f);

glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f);

glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd();

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}

void display (void) {
glClearColor (0.0,0.0,0.0,1.0);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

gluLookAt (0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

shader.bind();
cube();
shader.unbind();

glutSwapBuffers();
}

void reshape (int w, int h) {
glViewport (0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); //set up the double buffering
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("A basic OpenGL Window");

init();

glutDisplayFunc(display);
glutIdleFunc(display);

glutReshapeFunc(reshape);

glutMainLoop();

return 0;
}

Shader.vert

void main() {
gl_TexCoord[0] = gl_MultiTexCoord0;

// Set the position of the current vertex
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

Shader.frag

uniform sampler2D color_texture;
uniform sampler2D normal_texture;

void main() {

// Extract the normal from the normal map
vec3 normal = normalize(texture2D(normal_texture, gl_TexCoord[0].st).rgb * 2.0 - 1.0);

// Determine where the light is positioned (this can be set however you like)
vec3 light_pos = normalize(vec3(1.0, 1.0, 1.5));

// Calculate the lighting diffuse value
float diffuse = max(dot(normal, light_pos), 0.0);

vec3 color = diffuse * texture2D(color_texture, gl_TexCoord[0].st).rgb;

// Set the output color of our current pixel
gl_FragColor = vec4(color, 1.0);
}
VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 8.0/10 (3 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 2 votes)

36. OpenGL Framebuffers

Posted on : 22-04-2010 | By : Swiftless | In : OpenGL

Tags: , , , , , , , , ,

2

Introduction

Frame buffers are one of those mythical things that we have all heard of, but many beginner OpenGL developers avoid because there is not much information about them, and they can be confusing at first. A frame buffer can be thought of as another window that we render to, but we don’t end up seeing.

Now you might be thinking, if we draw something, but we don’t end up seeing it, then what is the point? Have you ever heard of off-screen rendering? I might ask you this instead, have you ever seen a reflection in a game of a live scene? Well, to get this reflection, we typically have to render the scene from the angle of the reflection first, and then we turn that render into a texture and bind it to whatever shape has the reflection attached to it. This initial rendering of the reflection is typically done in a frame buffer for speed, as we can bind a frame buffer straight to a texture.

If you have ever heard of pixel buffers, don’t get them confused with frame buffers, they are different, but can be used together. I won’t go into pixel buffers here, I might write a tutorial on them later on, but they are highly useful for asynchronous texture reads and writes. I once had a project, and part of it required I write to two frame buffers and read back the data, and then perform operations on this data and push it back to the GPU as a texture as quickly as possible. Using a combination of frame buffers and pixel buffers, I went from approximately 5 frames per second doing this, to 30 frames per second, and if the demand arises, I will post a tutorial on how to do this. It was a case where offloading the information to the GPU was not possible.

You should now have an idea of what frame buffers are, in short, they are a rendering context that can be bound to a texture, so let’s start coding them and see what we come up with. I am going to aim for a quad, with a texture of a rotating cube on it. It is a simple example, but highly useful, as you can imagine, the entire scene can be rendered into a frame buffer, and then placed onto a quad for some post processing.

Code

Frame buffer objects are stored like textures. OpenGL will store the information on the graphics card, and it will return an ID associated with that texture for us to place inside an unsigned integer. Also, as seen with textures, the frame buffer ID of 0 (zero) is reserved by OpenGL and is used to unbind the current frame buffer. Also, frame buffers can have several buffers attached. The default buffer is the colour buffer, but you can also bind depth buffers, stencil buffers, etc. So let’s create some variables to hold our frame buffer, frame buffers depth buffer and the texture we are going to store our frame buffer in.

unsigned int fbo; // The frame buffer object
unsigned int fbo_depth; // The depth buffer for the frame buffer object
unsigned int fbo_texture; // The texture object to write our frame buffer object to

After we have all the variables required to create and use our frame buffers (yes, we only need three variables), we are going to add some extra variables. First, we need two integer values for the width and height of our GLUT window, this is because when you create a frame buffer, you need to specify the width and the height of the texture, and when you use the frame buffer, you need to change the viewport size to match the texture size. Because frame buffers are independent of the size of the GLUT window, you can use them to create higher or lower resolution textures than your regular scene. Typically you would use a lower resolution texture for effects such as reflections so that it renders quicker. The last extra variable we are going to use will just hold how much our teapot in our frame buffer scene will rotate.

int window_width = 500; // The width of our window
int window_height = 500; // The height of our window

float rotation_degree = 0.0f; // The angle of rotation in degrees for our teapot

The next step we have to do is to create/initialize our frame buffer, the associated depth buffer, and the texture we are going to render to. Typically it is done in the following order:

  1. Create the Depth Buffer that we are going to use with our frame buffer.
  2. Create the Texture that we are going to bind our frame buffer to.
  3. Create the actual Frame Buffer.
  4. Bind the texture to the frame buffer.
  5. Bind the depth buffer to the frame buffer.
  6. Check for errors.

You can check for errors along the way if you wish, but I will just be using one check to make sure our final frame buffer is complete.

Frame Buffer – Depth Buffer

Let’s create the depth buffer we are going to use. To begin with, create a method call initFrameBufferDepthBuffer. This method is going to take no parameters and is not going to return anything. This method is going to contain all code related to the depth buffer we are going to use.

void initFrameBufferDepthBuffer(void) {

}

Inside of this method to create the depth buffer, the first call we need to make will create a render buffer for OpenGL to use, and is very similar to the code used to create textures.

glGenRenderbuffersEXT(1, &fbo_depth); // Generate one render buffer and store the ID in fbo_depth

This will create a render buffer, and store the ID in our fbo_depth variable for us to access.  Once the render buffer is created for the depth buffer, we then need to bind the buffer so that we can play with it and once we are finished with it, we need to bind the null render buffer, which takes the value of 0. When we are binding a frame buffer, it is once again very similar to texturing, so let’s place our binding code inside our method to fill between.

void initFrameBufferDepthBuffer(void) {
glGenRenderbuffersEXT(1, &fbo_depth); // Generate one render buffer and store the ID in fbo_depth
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_depth); // Bind the fbo_depth render buffer
...
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); // Unbind the render buffer
}

Next, we need to fill in the … between the binding of the render buffers. These next two lines are the lines that tell OpenGL that this render buffer will be used for depth. The first line tells OpenGL that we are going to be storing the depth component, and we are going to monitor the entire size of the window. The next line then says that we are going to use fbo_depth to render the depth buffer/attachment.

glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, window_width, window_height); // Set the render buffer storage to be a depth component, with a width and height of the window

glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Set the render buffer of this buffer to the depth buffer

Frame Buffer – Texture

Recapping on what we have done, we have created a render buffer that will store the depth component of the buffer that it is attached to. Now we need to create the texture that we want to store our frame buffer in. To do this, let’s create another method similar to the one we just created, but I am going to call this one initFrameBufferTexture. Because we are only creating a texture here, I am not really going to explain this code, the code comments should outline what is going on if you don’t know about texturing in OpenGL (in which case, you are diving in fairly deep straight out).

void initFrameBufferTexture(void) {
glGenTextures(1, &fbo_texture); // Generate one texture

glBindTexture(GL_TEXTURE_2D, fbo_texture); // Bind the texture fbo_texture

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard texture with the width and height of our window

// Setup the basic texture parameters

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

// Unbind the texture
glBindTexture(GL_TEXTURE_2D, 0);
}

Frame Buffer – Initialization

Finally, we need one more method; this one will be called initFrameBuffer and will make calls to the above methods we have created, as well as creating the frame buffer and attaching the texture and the depth buffer.

void initFrameBuffer(void) {
initFrameBufferDepthBuffer(); // Initialize our frame buffer depth buffer

initFrameBufferTexture(); // Initialize our frame buffer texture
…
}

After making the calls to our above methods, we need to create the frame buffer, and bind it. This is extremely similar to how we created the render buffer for the depth component, and how we create textures, so the following should look vaguely familiar.

glGenFramebuffersEXT(1, &fbo); // Generate one frame buffer and store the ID in fbo
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer
…
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our frame buffer

This code will generate one frame buffer, and then bind it so we can modify it, and then finally it will unbind it. This is fairly straight forward, and the next two calls will attach the texture and render buffer to our frame buffer. First off, let’s attach the texture to the frame buffer.

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo_texture, 0); // Attach the texture fbo_texture to the color buffer in our frame buffer

Now that we have a texture, theoretically we can use this straight out, but you won’t get any depth information. So we need to go ahead and attach the depth render buffer we created called fbo_depth, to our frame buffer.

glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Attach the depth buffer fbo_depth to our frame buffer

And now we have a frame buffer, which outputs to a texture and also has a depth buffer, which we can use. Well, we think we do, so first let’s check if our frame buffer is complete and there were no problems. To do this, we can make a call to glCheckFramebufferStatusEXT while our frame buffer is bound, and this will give us back a GLenum with the status of our frame buffer. For our frame buffer to be complete, we need to check that the status is equal to GL_FRAMEBUFFER_COMPLETE_EXT. We can do this with a simple if statement. Note that if you want the output to the console, you need to include <iostream> into your file.

GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); // Check that status of our generated frame buffer

if (status != GL_FRAMEBUFFER_COMPLETE_EXT) // If the frame buffer does not report back as complete
{
std::cout << "Couldn't create frame buffer" << std::endl; // Make sure you include <iostream>
exit(0); // Exit the application
}

General Initialization

Because in this example, we want to use the frame buffer constantly, I am going to create an init method which will call the initFrameBuffer method, and init will be called straight after we initialize GLEW, which is straight after we call glutCreateWindow. So here is our init method, which in this example, enables texturing, enables depth testing, and then initializes our frame buffer.

void init(void) {
glEnable(GL_TEXTURE_2D); // Enable texturing so we can bind our frame buffer texture
glEnable(GL_DEPTH_TEST); // Enable depth testing

initFrameBuffer(); // Create our frame buffer object
}

Next up, here is an example of my main method, which calls glewInit and calls our own init method.

int main (int argc, char **argv) {
…
glutCreateWindow ("You’re first OpenGL Window"); // Set the title for the window

if (GLEW_OK != glewInit()) {
std::cout << "Couldn't initialize GLEW" << std::endl;
exit(0);
}

init();
…
}

Frame Buffer – Usage

To use our frame buffer, I am first going to give you the display method, and whilst you could put all your code in here, I am going to make a call to a method to render our teapot scene. This display method builds upon the tutorial for creating a square.

So it looks something like the following code, which will create a square with texture coordinates, and I have placed it back 2 units so that it fills up most of the screen. Keep in mind, that I am not doing anything with the frame buffer at the moment; this is just a standard display method.

void display (void) {
keyOperations();

glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our window to red
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clear the colour buffer (more buffers later on)
glLoadIdentity(); // Load the Identity Matrix to reset our drawing locations

glTranslatef(0.0f, 0.0f, -2.0f);

glBegin(GL_QUADS);

glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner

glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner

glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner

glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner

glEnd();

glutSwapBuffers();
}

Now we will go ahead and bind our frame buffer texture to the quad. This is done just like binding a regular texture, because it is just a regular texture. The only difference between the texture we use for our frame buffer, and a standard texture we load in from a file, is that this texture is filled in on the GPU by OpenGL.

So right before your quad begins, bind your frame buffer texture, and then after you finish drawing your quad, unbind it.

glBindTexture(GL_TEXTURE_2D, fbo_texture);

glBegin(GL_QUADS);

…

glEnd();

glBindTexture(GL_TEXTURE_2D, 0);

You should be able to run this now, but unfortunately because we haven’t rendered anything into the frame buffer, nothing will appear on our quad, it will be as if we never bound a texture. So let’s create a method where we are going to render our frame buffer. I am going to call this renderTeapotScene, because I am using it to render a teapot.

void renderTeapotScene(void) {

}

renderTeapotScene is going to be called from inside our display method, right after our keyOperations and before we do any actual rendering.

void display(void) {
keyOperations();

renderTeapotScene();

...
}

Inside of our renderTeapotScene method, we need to first bind our frame buffer so that we can render to it, and then unbind it when we are finished rendering. I am also going to add in some extra code at the very end of this method, just to update the amount in which we are going to rotate our teapot.

void renderTeapotScene(void) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture

rotation_degree += 0.5f;
if (rotation_degree > 360.0f)
rotation_degree = 0.0f;
}

So far, everything should be fine, except when you bind a frame buffer, you need to set the size of the viewport that the frame buffer will render to. This is done with a call to glViewport, but first I am going to do some more management orientated activities, and store the current state of our GL_ENABLE_BIT and our GL_VIEWPORT_BIT. This is so that when we finish, we can put these back to how they were and not having any glEnable or glViewport calls modify our regular rendering. It is also wise to store information such as GL_LIGHTING_BIT if you are using lighting, and any other states you might need.

void renderTeapotScene(void) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states

glPopAttrib(); // Restore our glEnable and glViewport states
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture

rotation_degree += 0.5f;
if (rotation_degree > 360.0f)
rotation_degree = 0.0f;
}

It is our calls to glPushAttrib and glPopAttrib which will save and restore our states. The next step as I said is to set the viewport size for rendering, and then I am going to clear the colour buffer, depth buffer and reset the model view matrix, just like you would in your regular display method.

void renderTeapotScene(void) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states
glViewport(0, 0, window_width, window_height); // Set the size of the frame buffer view port

glClearColor (0.0f, 0.0f, 1.0f, 1.0f); // Set the clear colour
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the depth and colour buffers

glLoadIdentity();  // Reset the modelview matrix

glPopAttrib(); // Restore our glEnable and glViewport states
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture

rotation_degree += 0.5f;
if (rotation_degree > 360.0f)
rotation_degree = 0.0f;
}

This should be starting to look a little familiar inside of our frame buffer and push attributes calls, and you are probably right, everything you do from now on is just like rendering a normal scene, only you don’t need to call glFlush or glutSwapBuffers like you would with a regular render as we are not pushing the output to the screen. So now all we need to do is add the code in for our teapot rendering. I am going to translate it back five units, and then rotate it along the x and the y axis.

void renderTeapotScene(void) {
…
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the depth and colour buffers
glLoadIdentity();  // Reset the modelview matrix

glTranslatef(0.0f, 0.0f, -5.0f); // Translate back 5 units

glRotatef(rotation_degree, 1.0f, 1.0f, 0.0f); // Rotate according to our rotation_degree value

glutSolidTeapot(1.0f); // Render a teapot

glPopAttrib(); // Restore our glEnable and glViewport states
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture
…
}

If you followed everything as I have said correctly, then you should be able to compile this and run it. You should then see a quad with a red background, with a texture of a spinning teapot with a blue background attached to the quad.

Well done if you managed that, and now have your head around frame buffers!

If you have any questions, you can always contact me at swiftless@gmail.com

Tutorial Code

#include <GL/glew.h> // Include the GLEW header file
#include <GL/glut.h> // Include the GLUT header file
#include <iostream> // Allow us to print to the console

bool* keyStates = new bool[256]; // Create an array of boolean values of length 256 (0-255)

unsigned int fbo; // The frame buffer object
unsigned int fbo_depth; // The depth buffer for the frame buffer object
unsigned int fbo_texture; // The texture object to write our frame buffer object to

int window_width = 500; // The width of our window
int window_height = 500; // The height of our window

float rotation_degree = 0.0f; // The angle of rotation in degrees for our teapot

void initFrameBufferDepthBuffer(void) {

glGenRenderbuffersEXT(1, &fbo_depth); // Generate one render buffer and store the ID in fbo_depth
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_depth); // Bind the fbo_depth render buffer

glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, window_width, window_height); // Set the render buffer storage to be a depth component, with a width and height of the window

glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Set the render buffer of this buffer to the depth buffer

glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); // Unbind the render buffer
}

void initFrameBufferTexture(void) {
glGenTextures(1, &fbo_texture); // Generate one texture
glBindTexture(GL_TEXTURE_2D, fbo_texture); // Bind the texture fbo_texture

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard texture with the width and height of our window

// Setup the basic texture parameters
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

// Unbind the texture
glBindTexture(GL_TEXTURE_2D, 0);
}

void initFrameBuffer(void) {
initFrameBufferDepthBuffer(); // Initialize our frame buffer depth buffer

initFrameBufferTexture(); // Initialize our frame buffer texture

glGenFramebuffersEXT(1, &fbo); // Generate one frame buffer and store the ID in fbo
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo_texture, 0); // Attach the texture fbo_texture to the color buffer in our frame buffer

glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Attach the depth buffer fbo_depth to our frame buffer

GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); // Check that status of our generated frame buffer

if (status != GL_FRAMEBUFFER_COMPLETE_EXT) // If the frame buffer does not report back as complete
{
std::cout << "Couldn't create frame buffer" << std::endl; // Output an error to the console
exit(0); // Exit the application
}

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our frame buffer
}

void init(void) {
glEnable(GL_TEXTURE_2D); // Enable texturing so we can bind our frame buffer texture
glEnable(GL_DEPTH_TEST); // Enable depth testing

initFrameBuffer(); // Create our frame buffer object
}

void keyOperations (void) {
if (keyStates['a']) { // If the a key has been pressed
// Perform 'a' key operations
}
}

void renderTeapotScene(void) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states
glViewport(0, 0, window_width, window_height); // Set the size of the frame buffer view port

glClearColor (0.0f, 0.0f, 1.0f, 1.0f); // Set the clear colour
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the depth and colour buffers
glLoadIdentity();  // Reset the modelview matrix

glTranslatef(0.0f, 0.0f, -5.0f); // Translate back 5 units

glRotatef(rotation_degree, 1.0f, 1.0f, 0.0f); // Rotate according to our rotation_degree value

glutSolidTeapot(1.0f); // Render a teapot

glPopAttrib(); // Restore our glEnable and glViewport states
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture

rotation_degree += 0.5f;
if (rotation_degree > 360.0f)
rotation_degree = 0.0f;
}

void display (void) {
keyOperations(); // Perform any key presses

renderTeapotScene(); // Render our teapot scene into our frame buffer

glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our window to red
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clear the colour buffer (more buffers later on)
glLoadIdentity(); // Load the Identity Matrix to reset our drawing locations

glTranslatef(0.0f, 0.0f, -2.0f);

glBindTexture(GL_TEXTURE_2D, fbo_texture); // Bind our frame buffer texture

glBegin(GL_QUADS);

glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner

glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner

glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner

glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner

glEnd();

glBindTexture(GL_TEXTURE_2D, 0); // Unbind any textures

glutSwapBuffers();
}

void reshape (int width, int height) {
glViewport(0, 0, (GLsizei)width, (GLsizei)height); // Set our viewport to the size of our window
glMatrixMode(GL_PROJECTION); // Switch to the projection matrix so that we can manipulate how our scene is viewed
glLoadIdentity(); // Reset the projection matrix to the identity matrix so that we don't get any artifacts (cleaning up)
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 100.0); // Set the Field of view angle (in degrees), the aspect ratio of our window, and the new and far planes
glMatrixMode(GL_MODELVIEW); // Switch back to the model view matrix, so that we can start drawing shapes correctly
}

void keyPressed (unsigned char key, int x, int y) {
keyStates[key] = true; // Set the state of the current key to pressed
}

void keyUp (unsigned char key, int x, int y) {
keyStates[key] = false; // Set the state of the current key to not pressed
}

int main (int argc, char **argv) {
glutInit(&argc, argv); // Initialize GLUT
glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA); // Set up a basic display buffer (only single buffered for now)
glutInitWindowSize (500, 500); // Set the width and height of the window
glutInitWindowPosition (100, 100); // Set the position of the window
glutCreateWindow ("You’re first OpenGL Window"); // Set the title for the window

if (GLEW_OK != glewInit()) {
std::cout << "Couldn't initialize GLEW" << std::endl;
exit(0);
}

init();

glutDisplayFunc(display); // Tell GLUT to use the method "display" for rendering
glutIdleFunc(display); // Tell GLUT to use the method "display" for rendering

glutReshapeFunc(reshape); // Tell GLUT to use the method "reshape" for reshaping

glutKeyboardFunc(keyPressed); // Tell GLUT to use the method "keyPressed" for key presses
glutKeyboardUpFunc(keyUp); // Tell GLUT to use the method "keyUp" for key up events

glutMainLoop(); // Enter GLUT's main loop
}
VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.0/10 (11 votes cast)
VN:F [1.9.3_1094]
Rating: +6 (from 6 votes)

7. Maths Radians

Posted on : 25-03-2010 | By : Swiftless | In : Maths

Tags: , , ,

0

Welcome to Radians. Radians are a huge concept that really starts taking you into a new level of maths. Although, I personally find it rather simple. It is all about trigonometry. In fact it is the very core of trigonometry, only now we are going to see the whole picture.

Now there are two types of angles, you have your degrees which go up to which can range from 0 to 360 in a circle. And your radians which range from 0 to 2PI.

Hence:

0 degrees = 0 radians

90 degrees = PI/2 radians

180 degrees = PI radians

270 degrees = 3PI/2 radians

360 degrees = 2PI radians

Now lets just take a look at converting Degrees to Radians and Radians back to Degrees.

To convert from Degrees to Radians:

Degrees * PI / 180

Also written as:

Degrees / 180 * PI

To convert from Radians to Degrees:

Radians * 180 / PI

Also written as:

Radians / PI * 180

Now lets take a look at our Unit Circle from which trigonometry was born:

Radian Circle

Lookie, a right angled triangle!

Now this is a unit circle, as you can see, it has a radius of 1 unit.

So lets start taking a look at how we can find point P on that diagram.

Using our lovely trigonometry:

cos@ = x/1

therefore:

cos@ = x

!! We have our x position from our camera class in OpenGL !!

sin@ = y/1

therefore:

sin@ = y

!! We have our y position from our camera class in OpenGL !!

And now you have your point P. Simple isn’t it.

If you have any questions, please email me at swiftless@gmail.com

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 8.3/10 (4 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

6. Maths Trigonometry

Posted on : 25-03-2010 | By : Swiftless | In : Maths

Tags: , , ,

0

Trigonometry is based on triangles. The point of trigonometry is to find either the unknown side or angle of a triangle, when we know a side and an angle.

Here is a little diagram to get you started (pretty isnt it).
Trigonometry Triangle

Now:
O stands for opposite.
A stands for adjacent.
H stands for hypotenuse.
alpha is the angle in the corner where the angle is either known, or needed to be found.

Ok, now the 3 trigonomic functions are:
Sine, Cosine and Tangent

These will be known as:
sin, cos and tan on your calculator.

And respectively they each have their own inverse function known as:

sin^-1, cos^-1 and tan^-1

Here I am going to let alpha be @ as I dont have any alpha key to press :P
so to remind you alpha is our angle, so @ will be known now as our angle.

Now the
sin@ = o/h
cos@ = a/h
tan@ = o/a

You can easily remember this by a little saying:
soh cah toa

So why do we need this? We need this when we want to find the length of a side in a triangle. If you have the length A and the angle @, then you can use trigonometry to find either H or O. And likewise for the lengths H and O.

Next we can use trigonometry to find the unknown angle.

To do this, you start with your basic formula, eg:
sin@ = o/h

Then we have to get sin on the other side, so we times both sides by the opposite
of sine which is sin^-1, which should also be on your calculator.

so by doing this we end up with:

@ = sin^-1(o/h)

And that is all there is to trigonometry. You can find the sides and angles of a triangle using this.

But how would we use this in a game you might say. Well take a little look at my next diagram (god I love mspaint).

Trigonometry Circle

In the image above it shows you a rough idea of how you would make this into a camera for a game. You have yourself in the centre and have 360 degrees of rotation around. You can use trigonometry, and with your current angle, and knowing your current position to A(where you wish to go) you can determine your point at the corner of H and O.

But that is just a quick reference I whipped up in 10 minutes. In the Radian tutorial you will find out just how the camera class relates to trigonometry in detail.

If you have any questions, please email me at swiftless@gmail.com

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.5/10 (2 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

5. Maths Vector Dot Product

Posted on : 25-03-2010 | By : Swiftless | In : Maths

Tags: , , , ,

0

Here we are going to be looking at the infamous dot product AKA scalar product.

Dot products are used in computer programming to work out normals for 3d objects. A normal is a vector, perpendicular to the plane it is on.

I couldn’t really find a meaning to what the dot product actually is. So I am going to class it as a means of finding an angle or a length of a vector.

Now there are 3 main ways for writing a dot product equation.

a.b = a1b1 + a2b2 = |a| |b| cos @

Where a.b = [a1, b1] . [a2, b2]

a.b = a1 * b1 + a2 * b2

Which comes out the same as our second formula. While our third formula takes the length of a times by the length of b times by the cosine of theta where theta is the angle between vectors a and b.

Now if the angle between a and b is equal to 90 then a is perpendicular to b.

And that is all there really is to the infamous dot product. It is a rather simple concept really.

So lets have a little play with that. Say we have the points:

AB = [4, -2]

BC = [-1, -2]

And we want to find out if AB is perpendicular to BC. We now have to do the dot product. We cannot use the third method as we don’t know any angles, although we could work them out, but I will explain that in a different topic. As the third equation is simply ‘plug n play’, whack in the numbers and press the calculate button on your calculator.

So to find the dot product we get:

AB . BC

AB . BC = (4 * -1) + (-2 * -2)

AB . BC = -4 + 4

AB . BC = 0

Therefore AB is perpendicular to BC.

If you have any questions, please email me at swiftless@gmail.com

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 8.0/10 (2 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

4. Maths Vector Length

Posted on : 25-03-2010 | By : Swiftless | In : Maths

Tags: , , ,

1

The first thing we will look at is how to work out the length of a vector.

Vector Length 1

Take a look at the diagram and try to grasp that we can determine the length of every vector there.

————————Figure 1 – The triangle on the left———————-

First go to the iamge in the left. You will see a triangle with sides of length a, b and c.

The vector a is facing towards c, the vector b is facing towards a and the vector c is facing towards b.

So to work out the length of the vectors we start at the end of the vector WITHOUT the arrow and work our way around to the end with the arrow.

To work out the length of a, we would start at the end of a, so the start of b and work around to the end of a with the arrow. So our length would be:

a = -b + -c

Which comes down to:

a = -b-c

If we were to work out negative a, we would get:

-a = c + b

Because to work out the negative value, we start at the other end.

For our formulae for a to be:

a = -b-c

You have to take into account that moving in the same direction is positive and moving opposite to the arrow is negative.

So all our lengths for our triangle would be:

a = -b-c

b = -c-a

c = -a-b

————————Figure 2 – The square on the right———————-

Vector Length 2

If you follow our rules from above, the lengths of our vectors come out to:

a = -d-c+b

b = c+d+a

c = b-a-d

d = -c+b-a

Keep in mind that no matter what shape you have, you ALWAYS work it out the same way. And thanks to vectors being what they are, this will always work.

__LENGTH OF A VECTOR PART 2__

In this part, we are going to be looking at the length of a vector in almost the exact same way as before. Only this time, the characters, a,b and c are not lines, but points.

Vector Length 3

To work out the length of these, you just have to work it out a little differently.

Take point A and point C. Now the length of that vector is AC (with a line above it)

Vector Length 4

The arrow above it just represents a vector instead of a normal line.

So in this diagram we have lengths:

AC

CB

BA

And to work that out is exactly the same as before.

AC = |AC| or -|AB|-|BC|

Where the lines | | represent the length.

__LENGTH OF A VECTOR PART 3__

Here we are going to be acctually calculating the length of the vector using numbers.

Vector Length 5

A is going to be located at (1,1)

B is going to be located at (1,0)

C is going to be located at (2,0.5)

Now the line AC comes to:

AC = [cX - aX, cY - aY]

Therefore:

AC = [2 - 1, 0.5 - 1]

AC = [1, -0.5]

Now to work out the length/distance:

d = sqrt(x^2 + y^2)

And vectors dont acctually have a length measuring system like cm, m, km etc. They are just measured in units.

so AC = sqrt(1^2 + (-0.55)^2)

AC = sqrt(1 + 0.25)

AC = sqrt(1.25) units.

If you have any questions, please email me at swiftless@gmail.com

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 1.0/10 (1 vote cast)
VN:F [1.9.3_1094]
Rating: -1 (from 1 vote)

3. Maths Lines

Posted on : 25-03-2010 | By : Swiftless | In : Maths

Tags: , ,

3

I am going to start this tutorial now, but I probably will not have time to finish it. But here goes…

The equation of a line can be shown in 2 different forms. There is the General Equation and the Slope-Intercept form. They are:

General Equation: aX + bY = C
Slope-Intercept form: Y = mX + C

I find the slope intercept form best, as it tells you straight out where the formula crosses the y axis at X and the slope of the line is M.

Let us reuse this diagram:
Distance Formula Triangle

Now first we will look at the slope:
The formula for a slope between 2 points is:
M = y2-y1
——
x2-x1

Simple enough. Now to find C, we use the equation Y = mX + C:
(y2) = M * (x2) + C

So we are substituting in one of the set of points, also adding in M which we solved before.

so you end up with:
(y2)
—– – M = C
(x2)

Now that we have both C and M we can determine that the formula is:
y = mX + C by adding in the numbers for C and M.

Now that we have our formula in the slope-intercept form, what about converting that to the General form?

Y = mX + C

Y
— – X = C
M

I will add more onto this later, as it is a tad longer than the others. Stay tuned….

If you have any questions, please email me at swiftless@gmail.com

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 7.0/10 (1 vote cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

2. Maths Pythagoras Theorem

Posted on : 25-03-2010 | By : Swiftless | In : Maths

Tags: , , ,

2

Most people who have done maths in high school, would have heard of Pythagoras theorem.

This is used to work out the unknown side of a triangle, if you know the other 2 sides.

Pythagoras Triangle

Here you can see the sides, A, B and C.

Now Pythagoras theorem states that A^2 + B^2 = C^2

So if you know any two sides, you add them in, rearrange the formula if needed, and then you can solve for the unkown sides.

So how would you use this in a game? What about collision detection? Using this you can find quite easily in a 2 dimensional plane when 2 points will meet.

They will meet when A^2 + B^2 = 0

Quite simple really, you take the position of A and B on the X axis and do the equation, then if it comes up with an answer of 0, you then take the position of A and B on the Y axis, then if that also comes to 0, they must be colliding.

So to put that in other words, we are finding the distance :-) If the distance is nothing, then they are located in the same position.

Not sure if that is right, sounds right from my position, although it is 1:18 am.

If you have any questions, please email me at swiftless@gmail.com

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 7.0/10 (1 vote cast)
VN:F [1.9.3_1094]
Rating: +1 (from 1 vote)
Improve the web with Nofollow Reciprocity.