Jun
01
2009
0

Athena: Cheap(er) Per-Pixel Directional Lighting (cont)

In my previous blog entry, Athena: Cheap(er) Per-Pixel Directional Lighting, I wrote how I had an idea for post process lighting calculations. Well, like many other things, it has already been done before, in fact a long time ago, 1988. It is known as Deferred Shading.

The wiki article also mentions something else that I didn’t take into considering, and that is transparent objects, since there would be more than one lighting equation needed.

On the whole though, I’m glad I got a chance to implement it, one more thing I know how to do.

Written by Kaluriel in: Athena,Code,Shaders,Tutorials | Tags: , ,
May
31
2009
0

Athena: Cheap(er) Per-Pixel Directional Lighting

Per-Pixel Directional Lighting through Post ProcessAs mentioned in Athena: More Uses for Framebuffer Objects, I have thought up a way of doing lighting using colour buffers, at the moment it is only directional lighting however.

But the great thing is, depending on how many objects are in your scene, and how much overdraw can happen, this method is faster (I think, I don’t know the cost of writing to a second colour attachment).

Colour Shader

The colour shader is just a basic shader I’ve setup to show. First of all the vertex shader…

//
// Varying Variables
varying vec3 Normal;

//
// Vertex Shader entry point
void main()
{
Normal = normalize( gl_NormalMatrix * gl_Normal );
gl_Position = ftransform();
}

As you can see this is just a basic vertex shader, transforming a vertex position into screen space and passing the normal onto the fragment shader through a varying variable type.

Now the fragment shader…

//
// Varying Variables
varying vec3 Normal;

//
// Fragment Shader entry point
void main()
{
vec3 N = normalize( Normal );
float kDrawLit = 1.0;
gl_FragData[0] = vec4( 1.0, 0.0, 0.0, 1.0 );
gl_FragData[1] = vec4( N, kDrawLit );
}

This is a typical fragment shader as well, using draw buffer zero for the unlit texel colour. However, I’ve normalised the interpolated normal that was calculated for this texel and I’m outputting it to draw buffer one, along with another value ‘kDrawLit‘.

When the w component of draw buffer 1 for this texel is set to 0.0, the texel will not have any lighting calculations performed on it in the post process. I came up with this when I started thinking about rendering a HUD before the post processing.

I’ve chose just to output red as a colour, anything is fine, such as a texture that is mapped to the object in question.

Per-Pixel Lighting Shader

Again, another simple vertex shader, passing a transformed vertex and texture coordinate to the fragment shader…

//
// Varying Variables
varying vec3 v_lightDir;
varying vec3 v_halfVec;

//
// Vertex Shader entry point
void main()
{
//
v_lightDir = normalize( gl_LightSource[0].position.xyz );
v_halfVec = normalize( gl_LightSource[0].halfVector.xyz );

//
gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;
gl_Position = gl_Vertex;
}

Now for where the magic happens, the fragment shader, it uses two textures. The ‘baseImage‘ sampler is for the colour buffer, whilst the ‘nrmImage‘ is used for the normal texture we wrote…

//
// Uniform Variables
uniform sampler2D baseImage;
uniform sampler2D nrmImage;

//
// Varying Variables
varying vec3 v_lightDir;
varying vec3 v_halfVec;

//
// Fragment Shader entry point
void main()
{
// Get texel colour and normal data
vec4 kTexelColour = texture2D( baseImage, gl_TexCoord[0].xy );
vec4 kNormalColour = texture2D( nrmImage, gl_TexCoord[0].xy );

// Don't Perform Lighting on a non-lit texel
if( kNormalColour.w == 0.0 )
{
gl_FragData[0] = kTexelColour;
return;
}

// Calculate Ambient
vec4 kAmbient = gl_LightSource[0].ambient * kTexelColour;

// Process Light Direction and Normals
float NdotL = max( dot( kNormalColour.xyz, v_lightDir ), 0.0 );
vec4 kColour = kAmbient;

// Add Diffuse and Specular is NdotL is greater than zero
if( NdotL > 0.0 )
{
// Calculate Diffuse
vec4 kDiffuse = ( 1.0 - kAmbient ) * ( gl_LightSource[0].diffuse * kTexelColour );
vec4 kSpecular = gl_LightSource[0].specular;
float kShininess = 60.0;

float NdotHV = max( dot( kNormalColour.xyz, v_halfVec ), 0.0 );
kColour += kDiffuse * NdotL;
kColour += kSpecular * pow( NdotHV, kShininess );
}

// Write Pixel Colour
gl_FragData[0] = kColour;
}

As you can see, if the w component of the normal texture is 0.0 then the colour value is outputted as it is. If not, using the normal and the light currently setup, the colour is modified to be lit before being outputted.

I’ve just used a simple Blinn shader for calculating the lighting.

The Application

Now for the application side of things, below is just some quick sample code for what I used for my example. As you can see I’ve used a unsigned byte to store the normal, a floating point texture may have better accuracy at describing it though.

//
//
namespace CommonApp
{
enum TextureTypes
{
kColour,
kNormal,
kDepthStencil,
kNumTextureTypes,
};

//
const int kWidth = 800;
const int kHeight = 600;

//
GLuint l_frameBuffer;
GLuint l_textures[kNumTextureTypes];

//
GLuint l_colourProgram;
GLuint l_lightingProgram;
}

//
// Use alternate INTERNAL_FORMAT if floating point textures are not supported
//#define INTERNAL_FORMAT GL_RGBA
#define INTERNAL_FORMAT GL_RGBA32F_ARB

//
//
void CommonApp::Init()
{
// Code to load colouring shader program
// ...

// Code to load lighting shader program and setup uniform variables
// ...

// Generate Textures
glGenTextures( kNumTextureTypes, l_textures );

// Create Colour Texture
glBindTexture( GL_TEXTURE_2D, l_textures[kColour] );
glTexImage2D( GL_TEXTURE_2D, 0, INTERNAL_FORMAT, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, 0 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

// Create Normal Texture
glBindTexture( GL_TEXTURE_2D, l_textures[kNormal] );
glTexImage2D( GL_TEXTURE_2D, 0, INTERNAL_FORMAT, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, 0 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

// Create Depth Buffer
glBindTexture( GL_TEXTURE_2D, l_textures[kDepthStencil] );
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, kWidth, kHeight, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 0 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

// Generate Framebuffer and attach textures
glGenFramebuffersEXT( 1, &l_frameBuffer );
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, l_frameBuffer );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, l_textures[kColour], 0 );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, l_textures[kNormal], 0 );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, l_textures[kDepthStencil], 0 );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, l_textures[kDepthStencil], 0 );
}

//
//
void CommonApp::DeInit()
{
glDeleteFramebuffersEXT( 1, &l_frameBuffer );
glDeleteTextures( kNumTextureTypes, l_textures );
}

Just the usual code as you can see for setting up a frame buffer. Now for rendering the scene…

//
//
void CommonApp::Render()
{
// Use Frame Buffer
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, l_frameBuffer );

// Set Draw Buffers
const GLenum kBuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
glDrawBuffers( 2, kBuffers );

// Use Shading Program
glUseProgram( l_colourProgram );

// Perform Rendering
// ...

// Reset Draw Buffer
glDrawBuffer( GL_COLOR_ATTACHMENT0_EXT );

// Reset Frame Buffer
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
}

I’ve set it up so that drawing to draw buffer zero writes to the colour texture, whilst drawing to draw buffer one writes to the normal texture, to reflect what is being done in the shader.

You don’t need to use the colour shader I described up above, as long as it writes out the normal and an unlit colour, any shader can be used for this process, but for demonstration I’ve made it in this example that all geometry is drawn with this shader program.

Finally with our scene rendered, we can moved onto the final post processing stage…

//
//
void CommonApp::PostRender()
{
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, l_textures[kColour] );

glActiveTexture( GL_TEXTURE1 );
glBindTexture( GL_TEXTURE_2D, l_textures[kNormal] );

glUseProgram( l_lightingProgram );

// Render Fullscreen Quad
// ...
}

More Per-Pixel Directional Lighting through Post ProcessAttaching the colour and normal texture, using the per pixel lighting shader program and drawing a quad. The images within this blog are the final result (showing a comparison would be useless since they look the same).

One downside to this is that all texels have to use the same shininess value, however the alpha value of the colour buffer could be used to control this.

It is only a start, I need to performance check it at some point to see if it gives better or worse performance and under what conditions.

Download Source: Per Pixel Lighting (MacOSX)
Written by Kaluriel in: Athena,Code,Shaders,Tutorials | Tags: , ,
May
29
2009
0

Athena: More Uses for Framebuffer Objects

Depth Buffer using Frame Buffer ObjectAs I was upgrading my engine to the latest version of OpenGL, I noticed how my depth buffer was broken again (I use it for debugging my scenes when on the debug menu), and despite many changes, I was still having trouble getting it to display properly.

The glReadPixels() function with GL_DEPTH_COMPONENT was working, but I was having no luck at getting it displaying at any colour other than white without converting it first before writing it to a texture with glDrawPixels() – on reflection a floating point texture might have made this easier.

Anyways, when looking for answers, I found a way of using frame buffer objects to write out to multiple colour buffers, which allowed me to modify my Blinn shader to render a scene and the depth buffer to texture at the same time.

First of all, the shader needs to be shaders, instead of gl_FragColor, we use gl_FragData[n], where n is the index of the colour buffer we want to write to.

//
// Varying Variables
varying float v_farPlane;
varying float v_nearPlane;

//
// Fragment Shader entry point
void main()
{
// Write Pixel Colour
//gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
gl_FragData[0] = vec4( 1.0, 0.0, 0.0, 1.0 );

// Write Depth
float kDepth = 1.0 - ( gl_FragCoord.z / gl_FragCoord.w ) / ( v_farPlane - v_nearPlane );
gl_FragData[1] = vec4( kDepth, kDepth, kDepth, 1.0 ); // Luminace style
}

And finally when binding your frame buffer object.

//
//
void RenderTarget::Setup()
{
// Create Frame Buffer
glGenBuffers( 1, &m_frameBuffer );

// Bind Frame Buffer
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_frameBuffer );

// Attach texture to receive colour
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_colorTexture, 0 );

// Attach Texture to receive depth buffer
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, m_depthTexture, 0 );

// Attach Depth and Stencil Buffer (same object since my gfx card doesn't support them being seperate)
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_stencilDepthBuffer, 0 );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, m_stencilDepthBuffer, 0 );
}

//
//
void RenderTarget::StartRender()
{
// Bind Frame Buffer
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_frameBuffer );

// Set which index draws to which colour attachment
const GLenum kBuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
glDrawBuffers( 2, kBuffers );
}

The call to glDrawBuffers() sets where gl_FragData[x] is being wrote to, I’ve specified there are two indexes, the first one points to colour attachment 0, and the second points to colour attachment 1.

Now when an object is rendered using that shader, it will output the normal colour buffer to colour attachment 0, and output the depth buffer to colour attachment 1.

Also, don’t forget to reset the draw buffer destination after you’re finished with it.

//
//
void RenderTarget::EndRender()
{
// Reset draw buffer destination
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);

// Unbind frame buffer and all attachments
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
}

I will probably remove the glBindFramebufferEXT() call to unbind the frame buffer at some point, so that the same frame buffer gets used for all render targets, only the attachments get changed.

I’ve read it is faster this way. For more information on this, there is this great article on GameDev.net about it called, OpenGL Frame Buffer Object 201.

I probably won’t use this for writing out the depth buffer, but it did give me some ideas for per pixel lighting.

Written by Kaluriel in: Athena,Code,Shaders,Tutorials | Tags: , , ,
May
28
2009
0

Athena: OpenGL 3.0 Upgrade in Progress…

Building in progress...

I just upgraded to the latest version of gDEBugger, and it kept notifying me that a lot of my code is using deprecated functions as of OpenGL 3.0.

So I have begun the long task of converting code and shaders alike, hopefully in a positive step since it will mean my DirectX 10 port of the Athena engine will have little modifications to work like the OpenGL and vice versa.

These functions are the first on my list, they are used for rendering my geometry.

glTexCoordPointer()

glColorPointer()

glNormalPointer()

glVertexPointer()

These have been replaced with glVertexAttribPointer(), a more useful system so you can specify custom attributes a vertex has, and link them to attribute variables in shaders (shaders are required now for everything like DirectX 10). So for a simple array of vertices, I linked them to attribute variable in my shader which was bound to location 0.

//
// Bind VBO Object
glBindBuffer( GL_ARRAY_BUFFER, m_vertexBuffer );

//
// Enable vertex attribute streaming on location 0
glEnableVertexAttribArray( 0 /* location */ );

//
// Set attribute offset, size, and type details for location 0
glVertexAttribPointer( 0, /* location */
4, /* components */
GL_FLOAT, /* type */
GL_FALSE, /* normalize */
sizeof( float ) * 4, /* stride */
0 ); /* buffer offset */

I found out shortly after however that the index I was using for my vertex attribute is a reserved index by nVidia for their built-in attributes, as are 12 others.

0 – gl_Vertex
2 – gl_Normal
3 – gl_Color
4 – gl_SecondaryColor
5 – gl_FogCoord
8 – gl_MultiTexCoord0
9 – gl_MultiTexCoord1
10 – gl_MultiTexCoord2
11 – gl_MultiTexCoord3
12 – gl_MultiTexCoord4
13 – gl_MultiTexCoord5
14 – gl_MultiTexCoord6
15 – gl_MultiTexCoord7

So in the interest of keeping things sane I changed the location index to be 16, all that was needed was updating my shaders to use attributes rather than gl_Position, etc.

//
// Vertex Attributes
attribute vec4 a_vertex;
attribute vec2 a_texCoord0;

//
// Vertex Shader Entry Point
void main()
{
//gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;
gl_TexCoord[0].xy = a_texCoord0;

//gl_Position = gl_Vertex;
gl_Position = a_vertex;
}

You may have noticed that I don’t multiply my vertex by any transformation matrices, this is because my vertex coordinates for 2D are always in the range of -1.0 to 1.0. Doing it this way saves me changing projection matrix states whenever I want to draw 2D, so my projection matrix is always setup for 3D. Also, the source for this vertex shader program contains another attribute for the texture coordinate as well since I just copy-pasta’d my Bloom shader.

Now just two simple calls were needed to be added to my  shader program before it was linked, so that the vertex attribute is bound to the correct location.

glBindAttribLocation( m_program, 16 /* location */, "a_vertex" );
glBindAttribLocation( m_program, 17 /* location */, "a_texCoord0" );
glLinkProgram( m_program );

As you can see my vertex shader has a texture coordinate as well (I’m using my Bloom vertex shader as an example), so the final code for setting up the VBO for this is.

//
// VBO layout
struct TexturedVertex
{
float texCoord[2];
float position[4];
};

//
// Bind VBO Object
glBindBuffer( GL_ARRAY_BUFFER, myVBO );

//
// Enable vertex attribute streaming on location 0
glEnableVertexAttribArray( 16 );
glEnableVertexAttribArray( 17 );

//
// Set attribute offset, size, and type details for location 0
glVertexAttribPointer( 17, 2, GL_FLOAT, GL_FALSE, sizeof( TexturedVertex ), 0 );
glVertexAttribPointer( 16, 4, GL_FLOAT, GL_FALSE, sizeof( TexturedVertex ), sizeof( float ) * 2 );

I’m sure there is a preprocessor command to get the offset of a variable within a structure, but “sizeof( float ) * 2″ works as well. My code is a bit more complex than is shown here (I have a vertex format class that manages what needs to be set where, and something to managed state changes et cetera), but you get the idea of how it all works.

Well that was one big change down, on the next page of this blog entry will be another big change, replacing glMatrixMode() and glLoadMatrix().

Written by Kaluriel in: Athena,Code,Shaders | Tags: , ,

Pages: 1 2 3


Apr
15
2009
0

OpenGL with Cocoa: Part 3

Another part to my series of guides for programming in OpenGL with Cocoa. Yesterday I showed you how to actively render in OpenGL with Cocoa: Part 2.

CocoaGL - New Header Functions and AttributesThis entry however will show you how to make the OpenGL view the first responder to ‘messages’, so that you can get key input and control turning of the triangle. All of the new functions with the exception of “keyAction” are overloaded and so a part of the Cocoa view system.

The new attribute “m_keys” will be used for storing the status of the key being pressed, true if it is pressed, false if it isn’t.

CocoaGL - Reset Key StatusNow when the application is started, we need to reset the values for “m_keys” to false so that we don’t have uninitialized data. We can do this within the functions “awakeFromNib” or “initWithCoder” but I have chose to do it within “initWithFrame“.

With that done we need to implement our new functions. For “acceptsFirstResponder“, “becomeFirstResponder” and “resignFirstResponder” we return “YES” so that the OpenGL view class we are using gets the messages first instead of the main window.

CocoaGL - Handling Input and ResponseFor “keyDown” and “keyUp” we check to see if there is any input and then forward the information onto one of our own classes, “keyAction” with a value which specifies if the key is pressed or not. This is they set to the Boolean array a the appropriate index.

We could just use the “keyAction” function to control the triangle, however we would be limited in update cycles depending on the repeat rate of messages during a key press.

CocoaGL - Checking for InputNow during the “drawRect” function, we check the status of key presses within the Boolean array. If the key ‘A’ is pressed, we rotate the triangle left by one degree per frame. However if ‘D’ is pressed, it will rotate the triangle right by one degree per frame. And if neither are pressed, nothing will happen.

As before we are not using glLoadIdentity() so the resultant matrix from the last frame is being modified, not a new one which we would have to store and increment a rotational value for.

CocoaGL - Controlling the TriangleWith the new changes, build and run the application, and pressed ‘A’ and ‘D’ to watch the triangle rotate differently. In the previous guide it rotated constantly, however now it requires key input of specific keys to rotate it, and you have control over the direction of rotation.

Thats all for OpenGL with Cocoa for the moment. Still working out some of the bugs in my own applications as I convert them from GLUT, so hopefully the next guide will show you how to switched between window and fullscreen modes.

Download Source: CocoaGL Source (Part 3)
Written by Kaluriel in: Code,Tutorials | Tags: , , , ,
Apr
14
2009
0

OpenGL with Cocoa: Part 2

Following on from yesterdays entry, OpenGL with Cocoa: Part 1, this entry will expand upon that.

CocoaGL - New Header FunctionsFirst of all, we need to add some new functions to our OpenGL view class, as well as a few attributes. “m_rectView” will be used to store the current window rectangle, whilst “m_timer” will be used for updating the window for redraw.

The “initWithFrame” function is called before the OpenGL context is setup, it is used to set the pixel format conditions for the context. The other functions are called by our own code.

CocoaGL - New Source FunctionsI’ve image to the right shows the source for the new functions. Within the “initWithFrame” you can see we’re requesting a format with a double buffer, accelerated hardware, 32 bit colour buffer, with 24 bit depth buffer and an 8 bit stencil buffer. We then call the same function within the NSOpenGLView class we’re inheriting off.

The “setupAnimationTimerWithInterval” function sets up a timer object that fires “timerUpdate” at a specified interval. That function calls “setNeedsDisplay” to make the window redraw. The framerate can be killed if we draw in both the “timerUpdate” function and the “drawRect” function.

CocoaGL - More New Source ChangesWithin the “prepareOpenGL” function, we call the “setupAnimationTimerWithInterval“. Now within the “drawRect” function, we call “resizeGL” which if the rectangle is different to a previously stored one, we make a call to glViewport() to update the destination bounds.

We also change the glFlush() call to a call to a call to “flushBuffer” call from the current OpenGL context, this is because we are now rendering with a double buffer instead of a single buffer.

CocoaGL - Final Output Window

You may have also noticed there is a call to glRotated(), since we don’t call glLoadIdentity() every frame, this will rotate our rectangle, showing that our application is running and updating consistently.

If all goes well, you should have an output like the one in the right image (well at some point since it is rotating).

Well that is all for using OpenGL with Cocoa for the moment, the next part will cover basic keyboard input.

Download Source: CocoaGL Source (Part 2)
Written by Kaluriel in: Code,Tutorials | Tags: , , , ,
Apr
13
2009
0

OpenGL with Cocoa: Part 1

CocoaGL - Creating an Application

In a previous entry I said I would show how to setup an OpenGL application using Cocoa. This guide will be slightly more thorough than the one written on the Apple Developer Site. The version of XCode I’m using is 3.1.3, but I’ve included lots of pictures, which will hopefully work around problems with changes in versions.

CocoaGL - Project is Setup

First off, this is an extremely basic program, single buffer which is only redrawn when the window’s rectangle is dirty. To start off, open up a copy of XCode and create a new “Cocoa Application” and give it a name. I named mine “CocoaGL“.

Once created you should have something that looks kinda like the image on the right.

CocoaGL - Adding Framework

Now you have setup a basic Cocoa application, if you click “Build and Go” you will have a Cocoa window being displayed, however if you click the Red button to close the window, the debugger is still running because the application is still active.

But we’ll get around to fixing that later. Now for using OpenGL, we’ll need the OpenGL framework (a framework is a special folder that contains headers, resources, libraries, etc for a particular third party library).

CocoaGL - Select OpenGL Framework

To add a framework to an application, right click on any folder in the project (I use an already created one), select “Add” and then “Existing Frameworks…“. Now to find the OpenGL framework, navigate to “/System/Library/Frameworks/“. Now search through the folder and select “OpenGL.framework“, and select “Add“, and “Add” again.

CocoaGL - Add Files

With the OpenGL library now linked to the application, we need an Objective-C class for our OpenGL window to be associated with. To do this, we’ll need to inherit off NSView or NSOpenGLView (with NSView we’ll need setup OpenGL ourselves, so for now we’ll use NSOpenGLView). Right click on a folder in the project again, but this time select “Add” and then “New File…“.

CocoaGL - Cocoa Class Source File

Select “Objective-C class” from the list. You can also “Objective-C NSView subclass“, which will create a class with the functions “initWithFrame” and “drawRect“, as well as inheriting off NSView. But I’ll be providing the code for the class so any Objective-C class will be fine.

CocoaGL - Name Source and Header

Upon clicking “Next” you’ll be presented with a screen similar to the one on the left. Choose a filename, for my code I used the name “OpenGLView” (this will also determine the class name. Make sure a header is created with this source file, one nice thing about XCode compared to Visual Studio is that it gives you this option.

CocoaGL - Default Objective-C Class

Click “Finish” and your source and header files will be created for you, opening the header for you to view straight away. I’ve shown what is given by default, this can be used for normal window associated stuff, but it lacks an OpenGL context as well as setting up the pixel format information, that will allow us to use OpenGL.

CocoaGL - New Class Header

Change the inherited class to NSOpenGLView (this does all the default stuff for us). Now add two addition functions, “prepareOpenGL” and “drawRect“, check the header for NSOpenGLView or the Cocoa documentation for more information. The image to the left shows what parameters and return value the functions use.

CocoaGL - New Class Source

Now open the source file (Objective-C uses the extension .m, while Objective-C++ uses .mm). Within the “prepareOpenGL” function, this is where we setup our OpenGL context, I’ve set the clear color and I’ve set the swap interval to be synchronized with the vertical refresh (vblSynch value needs to be set to 1, 0 is as immediate).

CocoaGL - Selecting a XIB

And the “drawRect” function is used for, as you may have guessed, redrawing our screen. For now I’ve added code to clear the screen, draw a yellow triangle and flush the buffer (glFlush is used for a single buffer, rather than double).

With that done we need to link a window to the class we’ve just created. So find the XIB file within the project, and double-click it to open it up Interface Builder.

CocoaGL - Adding a Custom Object

Within the Library window of Interface Builder, do a search for “Custom View“, then drag and drop the found object onto the window, and resize it if you want to be the same size as the window. There is also an “OpenGL View” object that gives you more control over the default settings, however I find it more restrictive to use.

CocoaGL - Sub Window Resize

Now open the “Size Inspector” window for the object we’ve just created, if it isn’t already open, goto the “Tools” menu and select “Size Inspector“. Click all arrows within “Autosizing” so that the object will automatically resize when the parent window is resized. See the image to the left for more information.

CocoaGL - Setting Sub Window ClassNow open up the “Identity Inspector“, if it isn’t open already you can access it from the “Tools” menu as well. Within the “Class Identity” section, set the “Class” to the name of the OpenGL view class we created, the auto-complete will help you find it. Once this is done, goto the “File” menu and select “Build and Go in XCode” – this will exit Interface Builder, build the project and then start it running.

CocoaGL - Build and Run

If all has gone well, you’ll see a window like the one on the left image. However, if you try to resize it, it will remain in the same place (this is because we didn’t change the viewport size when the window is resized, this will be covered in the next part of this guide to using OpenGL in Cocoa).

One other thing you’ll notice is that if you close the window the application will still be running as mentioned earlier.

CocoaGL - Setup a Delegate Class Header

To fix this, we need to setup an object to handle delegations from the application, one of which is whether the application should end if a window is closed. So as before when we created our “OpenGLView” class, create a new class, I’ve called mine “AppDelegate“.

When it is created, add the function “applicationShouldTerminateAfterLastWindowClosed“.

CocoaGL - Setup a Delegate Class Source

Now add the function to the source file as well, returning “YES” so that the application will end when a window is closed.

Now find the XIB file again and double-click to open it up with Interface Builder again.

CocoaGL - Add an Object to use as a Delegate

Now search for “Object“, and drag and drop the NSObject (the blue cube on its own, not the blue cube within the green circle) into the XIB window. Open up the “Identity Inspector” for the Object just created and then set the Class to the application delegate class we just created.

CocoaGL - Set Object Class

Now we just need to link the application delegate to this newly created Object associated with our delegate class. To do this, select “Application” from the XIB window, then open the “Connections Inspector“, available from the “Tools” menu.

CocoaGL - Set Object as Application Delegate

Now drag from the “delegate” selection circle, to the delegate object. If done successfully, “delegate” will have a shaded box around it and the name of your delegate class you created on the right.

Go to the “File” menu and select “Build and Go in XCode“, you should now have a basic OpenGL application made in Cocoa, with a window that will shutdown the application if the window is closed.

The next guide will cover rendering with a double buffer, handling resizing, and a render loop of 60 frames per second.

Download Source: CocoaGL Source (Part 1)
Written by Kaluriel in: Code,Tutorials | Tags: , , , ,
Mar
26
2009
0

My father… was a programmer… and a fiend…

Stencil BufferRecently I’ve been working on some functionality on one of my own games. The main problem I’ve been having is gDEBugger is no longer in the Beta stage for the Mac, and so my temporary license has run out. At some point I do plan to buy a license, but for the moment I’m limited to my own OpenGL debugging.

So I got inspiration to make a shader to render my stencil buffer for easier debugging. It works like this, after reading the stencil from my Frame Buffer Object (FBO), I render it to a fullscreen quad. During the Fragment Shader process, I read the pixel from the stencil texture, separating a single component (I choose red), I then use this to sample a pixel from a 1D texture (256 pixels wide since the stencil is 8bit, each with a unique colour).

Depth BufferThere are other applications I found for this, such as rendering the depth buffer as well, usually the depth buffer is practically white, and make it difficult to see objects far away. Of course, using many colours to do this, make it almost impossible to understand it. And because its a 1D 256 pixel texture, it doesn’t show the full range of depths since the depth buffer I’m using is 24bit.

It does demonstrate however how the depth buffer gets less accurate the further away an object is. the colours get further and further apart. This can be remedied by increase the number of bits a depth has, or reducing the difference between the near and far plane. Or you could do multiple renders (back to front) rendering the different distant objects, clearing the depth buffer after each render.

Though that is a little overkill. I do love the effect of the stencil buffer shader on the depth buffer though, reminds me of Commodore 64 crashes.

Written by Kaluriel in: Code,Courage,Programming | Tags: ,
Mar
17
2009
0

gDEBugger

gDEBuggerI’ve recently been taking part in beta testing the new gDEBugger for MacOSX. A fantastic program that for those who have used GPAD when developing for the PS3, or PIX when developing for the XBox360 will find familiar.

It gives details information about bottlenecks in your rendering, things that may be wrong, state changes that weren’t necessary, etc. And another useful thing, it allows you to view your textures, their mip maps, your frame buffers, and more importantly, depth and stencil buffers.

Today the license I was given expired since it is now out of beta and available to buy, though they were kind enough to give me a promotional code that would give me 15% off when I purchase.

I recommend it to any OpenGL developer, its helped improve my own game engine by showing me flaws in what I was doing.

Written by Kaluriel in: Code,Programming | Tags: ,
Mar
11
2009
0

Maya, Textures and Bloom

Stencil and BloomI recently finished my COLLADA to Geometry converter (Donatello). Now I can export a scene from Maya and convert its geometry as well as create a scene file (the scene file contains a list of geometry files to load, how many instances, and their transformation matrix in the world). There is a bug though, the way I created the ground, when triangulation is happening, the normals appear to get broken and cause different shades on the ground.

I also created a program to convert images into a texture which contains information about its width, height and depth, as well as create mipmaps. It doesn’t at the moment support compression, I’m starting to think maybe I should use dds files since I recently found out that they can be used with OpenGL (if you have a DirectX header). For now though, it works, and so I’ll keep using my own format.

I’ve also been modifying my bloom algorithm, this one seems to work a lot better with my scene. I’ve noticed my messing around also gives a great refraction effect (see the red area).

Written by Kaluriel in: Code,Programming | Tags: ,

Theme: TheBuckmaker.com Blog Themes | The best Webhosting Plans, Eigenes Internet Radio