Category: OpenGL

Vertex array objects

With openGL 3 came a few cool features most of these are pretty small and quick to learn, VAOs are among these, I really didn’t want to write a full fledged tutorial about it before, but seeing as I’m changing the format to promote shorter and more article like posts, it seemed like as good as place as any to start.

There hasn’t been that much written about the vertex_array_object extension, also there is some confusion on where to use it and how.
Simply put it couldn’t be simpler, it’s used to make the daily life of using VBOs easier and the code prettier, earlier you had to call these three functions for each buffer to set up rendering, normally that would be at least 3.

glEnableClientState
glBindBuffer
glTexCoordPointer Read more »

Recent updates

Ok, a lot has happened recently, so let me update you on things and thoughts I had.
First, I finally got a real job, I am now a professional web programmer, not exactly my first choice but hey you can’t get it all, well at least it allows me to develop some ideas I have while I’m getting paid for doing things, and the upside is that it’s a pretty flexible job, being deadline based and all, I can take an extra long lunch if I need to as long as I get things done on time.
Fortunately I do a lot of back end work so deadlines and jobs are reasonably evenly spaced and phased, most of the time.

Anyway moving on to anime, my current anime viewing list is

Slayers revolution
Zero no tsukaima 3
Sekirei
Nogizaka Haruka no Himitsu
Mission-E
ToLoveRu – Trouble

See at least some of them or forfeit you license to be of the ruling class when I take over the world. Read more »

OpenGL whish list 3.0

It’s been a while, and no it’s not because of the computer, it’s because of time, time and lack of things to write about, though not this time, this is something I wanted to write all this year.
In the beginning I was just collecting my thoughts, though I really should have written it down somewhere, then as months progressed I had less and less time to think about this.
However a few things lately caught my eye that made me rethink.

1. A while back Nvidia acquired Aegia, the physics chips maker, at first I thought “great now they will add a physics sub processor to every graphics card”.
No, they added it trough cuda, and I didn’t get it since although the gpu can do it well, any use of the gpu limits your frame rate, and that is generally considered bad.
In essence computing more objects means you can render less objects. Read more »

Playing catch up

This post will be the last one I write… on this computer, the reason being the pile of assorted powerful computer parts on the floor, though it will take some time before it can permanently turn this computer off, but it’s worth it.
I chose an Intel core 2 quad cpu and the new 9600gt (which is so hot of the manufacturing floor it’s still sort of luke warm) series among other things.
But for now prepare for another composite post.

anime:
I suggest these series (in no apparent order), see them or fail as a human being.

Lucky star
Minami-ke
Minami-ke Okawari
You’re Under Arrest! Full Throttle
Haruhi
Goshuushou-sama Ninomiya-kun
Hayate no Gotoku
Rosario + Vampire Read more »

GL wish list 2.0

A bit more than a year ago i posted a sort of wish list i wanted for openGL or computer graphics in general, a lot has happened since then, bu then again not enough has happened, so here is version 2.0 of that list, some things are off it and some things are new.

1. Z-buffer improvements.
Nothing has happened on this area besides for one thing, Nvidia released a sort of a tip at this years GDC to normalize the otherwise logarithmically spaced z buffer to something more linearly spaced, i haven’t tested it yet but i will.
According to them it’s sort of an hack that has a few problems, so i still really wish that we get the 64bit z buffer which will cause a shift that i will be talking about in point 2.

2. 64 or 128 bit floats.
Although we barely have 32 bit float textures i really do feel that we need to expand on this, at least internally in the shader units, this would definitely help with stuff like blurring shaders, extreme multi sampling shaders.

3. Virtual texturing.
Now this is one of the areas where most progress has been made, the new texture arrays or texture buffer objects really opens up the texturing bit, now with these there is not really a limit on how many textures you can have, i think the limit of the number of textures is now about 2048, it used to be 4 just a few months ago.
But still i really feel more can be done, Longs peak will take a step forward, but i want all limitations removed.

4. Blend shader.
This is something that came out of the many conversations on opengl.org i had with the various industry people there.
Basically what it is is a fourth shader stage that comes after the fragment shader.
What it does is that it takes the various bits of data generated by the fragment shader + whatever is in the current fragment of the render target and then output it to the specific fragment, no texture reads needed besides the render target, most often it would be just a simple pass trough shader.
There are many many new cool things you could do with this, like that layered rendering i was talking about the last time, coincidently this is why it’s not on the list currently.

5. Texture sampling.
I all actually pretty tired of mipmaping, it bugs me that the best hardware supported texture sampling method is actually a hack, i really want some kind of high quality projection centric gaussian texture sampling, or well at least something better than what we have now.

6. Raytracing.
Now i can’t stress it hard enough, raytracing will truly bring a revolution in graphics, well ok perhaps not, it is just another evolution, a great one but still.
And it wouldn’t be that hard to implement, for one it could be done in a shader, just place all the polygons to test in a texture buffer object and start testing, now that wouldn’t be all that effective.
So the next step would be some kind of specialized circuitry to make it faster.
I would suggest some kind of modified memory, a grid processor array of SPPUs (Single Purpose Processing Unit), they each contain the plane equations for one or at most a few polygons and a small and super simple set of gates that tests the polygon against the incoming ray and returns the distance and polygon id to a special router on the chip that decides what polygon id’s to return to the card based on the distance.
Doing it like that does mean that you can literally can fit thousands of processors on a simple little chip and that will cut down the ray test time from something unmanageable to something that more resembles a texture lookup.
And it’s just not graphics that will be affected by this, GPGPU physics will also do so and many many more things, i couldn’t really say because i don’t really know, it’s all new to everybody.

Well that’s all for now, perhaps i will revisit in a year or so.

PCF

In the last previous tutorial we explored the depth shadow maps in all it’s aliasing glory.
I showed you ho to fix the steep angle artifacts by using the diffuse term, and the shadow poping by adding a bias to the shadows.
In this lesson we are going to implement something called Percentage Closer Filtering or PCF as it is more commonly called, the name doesn’t exactly reveal what it does.
It is in fact a way to multi sample the shadows and this is pretty simple, so simple that i am not going to supply you with anything other than the new shader file, the rest is exactly the same as tutorial 03a.

1. transform the texture coordinates first two values by a really small amount.
2.make a shadow test against those coordinates.
3. repeat 1 and 2 as many times as needed..
4. take the collective result from the shadow tests and divide it with the number if samples you just did.

Lets demonstrate this with some code.
First we set up some variables + load the other textures besides the shadows.
Since we are also going to do 25 samples we want to eliminate as much as possible from the loop, that is why i added the inverted bias to gl_TexCoord[2].z instead of the shadow value.


float blur_spread[5];
blur_spread[0] = -0.003;
blur_spread[1] = -0.001;
blur_spread[2] = 0.000;
blur_spread[3] = 0.001;
blur_spread[4] = 0.003;

float samples=1.0/25.0;

gl_TexCoord[2] = gl_TexCoord[2]/gl_TexCoord[2].w;
gl_TexCoord[2]=(gl_TexCoord[2]+ 1.0) * 0.5;

gl_TexCoord[2].z -=0.005;
vec4 base = texture2D(texunit0, gl_TexCoord[0].xy);
vec3 norm = texture2D(texunit1, gl_TexCoord[0].xy).xyz*2.0-1.0;

float shade=0.0;
float shadow=0.0;

int x=0;
int y=0;

next do the sampling, note that because a division is more problematic than a add, we pre divided the samples so instead of adding one for each sample we are adding 0.04, this saves us the trouble of having to divide at runtime.


for(x=0;x<5;x++)
{
for(y=0;y<5;y++)
{
shadow = texture2D(texunit2,gl_TexCoord[2].xy+vec2(blur_spread[x],blur_spread[y]));
if(shadow > gl_TexCoord[2].z)
shade+=samples;
}
}

Great now all we have to do is include the rest and we are done


norm = normalize(gl_NormalMatrix * norm);
float fresnel =max((norm.z-0.6)*-1.0,0.0);
float diffuse = max(dot(lightVec, norm),0.0);
float specular = max(dot(reflect(lightVec,norm), viewVec), 0.0)*1.7;
specular=pow(specular,8.0);
shade*=diffuse;
gl_FragColor = (base* shade)+(vec4(0.0,0.1,0.3,0.0)*fresnel)+
(vec4(0.5,0.5,0.4,0.0)*specular*shade);

You can now begin to play around with the numbers, increasing the values in blur_spread will make it a bit more blurry, but then other artifacts show up, these can be fixed by fiddling with the bias parameters, but ultimately PCF is just a hack and won’t work every time.
I originally planned to include a version that changed the blurriness according to the distance from the shadow casting surface, it looked pretty good, unfortunately not good enough in all situations, it was done by getting the distance between the fragment and the shadow map depth value and with this manipulating the values in blur_spread.
It would have worked if it whereat for those meddling kids(read:artifacts).
Test and see if you can do it.

Download the new shader file for this tutorial, to get the rest download the previous tutorial

Depth Shadow maps

Shadows are always nice, but they can sometimes be a hazzle to implement, i am going to show you the simplest way to implement them in a method called projected depth shadow maps.
I am also going to bring up a way to create some nice shadows and light effects.

But first some theory, what we are going to do is.
1. render the depth to a texture, i will use a FBO here since they are nice an easy to use.
2. i am going to compare this map with the distance from the lightsource to what i am going to render.
3. finally we have to mask all the artifacts, and believe me, there are plenty of them there.

Now the real problem here is the texture projection, but fortunately openGL and glsl has some tricks up it’s sleeve.
What you do is you first make two matrices, one projection and one modelview matrix, we do the same with the rendering matrices to insure we will get the same every time.
Next we multiply the lightprojection and lightmodelview matrices into a temp matrix.
Then we combine that matrix with the inverted camera matrix and call it the texture matrix.

When we render the final rendering we then need to feed openGL with the new texture matrix, normally this is normally done with glTexGen, but we are going to take a little shortcut by directly uploading it with glLoadMatrixf.

Then in the shader we call a simple little code to buid new texture coordinates
gl_TexCoord[2] = gl_TextureMatrix[0]*gl_ModelViewMatrix*gl_Vertex; // in the vertex shader

gl_TexCoord[2] = gl_TexCoord[2]/gl_TexCoord[2].w; // fragment shader
gl_TexCoord[2]=(gl_TexCoord[2]+ 1.0) * 0.5;

now you need only use this texture coordinate and then compare the resulting texture lookup with the third parameter in the texture coordinate to determine if it’s in a shadow or not.

Sounds simple, so let’s get cracking

First of all this lesson is based on lesson 2c + the FBO parts of lesson 1, so all the helper funcs are there then we need two more functions.


void Combine_Matrix4(float MatrixA[16],float MatrixB[16], float *retM)
{
float NewMatrix[16];
int i;

for(i = 0; i < 4; i++){ //Cycle through each vector of first matrix.
NewMatrix[i*4] = MatrixA[i*4] * MatrixB[0] + MatrixA[i*4+1] * MatrixB[4] + MatrixA[i*4+2] * MatrixB[8] + MatrixA[i*4+3] * MatrixB[12];
NewMatrix[i*4+1] = MatrixA[i*4] * MatrixB[1] + MatrixA[i*4+1] * MatrixB[5] + MatrixA[i*4+2] * MatrixB[9] + MatrixA[i*4+3] * MatrixB[13];
NewMatrix[i*4+2] = MatrixA[i*4] * MatrixB[2] + MatrixA[i*4+1] * MatrixB[6] + MatrixA[i*4+2] * MatrixB[10] + MatrixA[i*4+3] * MatrixB[14];
NewMatrix[i*4+3] = MatrixA[i*4] * MatrixB[3] + MatrixA[i*4+1] * MatrixB[7] + MatrixA[i*4+2] * MatrixB[11] + MatrixA[i*4+3] * MatrixB[15];
}
memcpy(retM,NewMatrix,64);
}

void Inverse_Matrix4(float m[16], float *ret)
{

float inv[16]; // The inverse will go here

inv[0] = m[0];
inv[1] = m[4];
inv[2] = m[8];
inv[4] = m[1];
inv[5] = m[5];
inv[6] = m[9];
inv[8] = m[2];
inv[9] = m[6];
inv[10] = m[10];

inv[12] = inv[0]*-m[12]+inv[4]*-m[13]+inv[8]*-m[14];
inv[13] = inv[1]*-m[12]+inv[5]*-m[13]+inv[9]*-m[14];
inv[14] = inv[2]*-m[12]+inv[6]*-m[13]+inv[10]*-m[14];

inv[3] = 0.0f;
inv[7] = 0.0f;
inv[11] = 0.0f;
inv[15] = 1.0f;

memcpy(ret,inv,64);
}

THese will help with some of the matrix math, once you start making more advanced stuff you should put all of this in a larger class.

Next we set up the fbo


glBindTexture(GL_TEXTURE_2D, depth_tex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 2048, 2048, 0,
GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL );
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,
GL_TEXTURE_2D, depth_tex, 0);

glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, color_rb);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_RGBA,2048, 2048);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,
GL_RENDERBUFFER_EXT, color_rb);

Then in the update function we need to build all five matrices, these matrices are really only float[16].


glPushMatrix();

glLoadIdentity();
gluPerspective(45.0f, (float)800/600, 10.0f, 1000.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, cameraProjectionMatrix);

glLoadIdentity();
gluLookAt(0, 17, 46,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
glRotatef(angle,0.0f,1.0f,0.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, cameraViewMatrix);

glLoadIdentity();
gluPerspective(65.0f, 1.0f, 25.0f, 200.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, lightProjectionMatrix);

glLoadIdentity();
gluLookAt( lpos[0], lpos[1], lpos[2],
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
glRotatef(angle,0.0f,1.0f,0.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, lightViewMatrix);

glPopMatrix();

float tempa[16];
float inverted[16];
Inverse_Matrix4(cameraViewMatrix,inverted);

Combine_Matrix4(lightViewMatrix,lightProjectionMatrix, tempa);
Combine_Matrix4(inverted,tempa, textureMatrix);

Notice that we invert the cameraViewMatrix and combine it with the combined light matrix, we do this to cancel out the camera movement, this moves the texture matrix from world space to camera space and it’s what allows us to move things about without it getting all “funky”.
Next we have the renderplane function, i won’t explain it but it draws a single quad, super simple.
Then we are going to start rendering, first the light pass., it’s simple enough, but instead of the usual glTranslatef and glRotatef we load our premade matrices.


glViewport (0, 0, 2048, 2048);
glClearDepth (1.0f);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
checkfbo();
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity ();

glMatrixMode(GL_PROJECTION);
glLoadMatrixf(lightProjectionMatrix);

glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(lightViewMatrix);

glColor3f(1,1,1);

cv90_render();

Then we set up a few things


glViewport (0, 0, 800, 600);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glClearDepth (1.0f);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity ();

glMatrixMode(GL_PROJECTION);
glLoadMatrixf(cameraProjectionMatrix);

glMatrixMode(GL_TEXTURE);
glLoadMatrixf(textureMatrix);

glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(cameraViewMatrix);
glColor3f(1,1,1);

if (useshader) glUseProgramObjectARB(ProgramObject);

sendUniform1i("texunit0", 0);
sendUniform1i("texunit1", 1);
sendUniform1i("texunit2", 2);
sendUniform3f("lpos", lpos);

Now comes the fun bit, just make a note that we are not doing anything funny here, it’s a simple setup of multi texturing and then the rendering.


glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,tex1);

glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,tex2);

glActiveTextureARB(GL_TEXTURE2_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,depth_tex);

cv90_render();

//switch to the ground texture
glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D,tex3);
glActiveTextureARB(GL_TEXTURE1_ARB);
glBindTexture(GL_TEXTURE_2D,tex4);

RenderPlane();

glActiveTextureARB(GL_TEXTURE2);
glDisable(GL_TEXTURE_2D);

glActiveTextureARB(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);

glActiveTextureARB(GL_TEXTURE0);
glDisable(GL_TEXTURE_2D);

if (useshader) glUseProgramObjectARB(0);

glFlush ();

Ok on to the shader parts.

Vertex shader


uniform sampler2D texunit0;
uniform sampler2D texunit1;
uniform vec3 lpos;

varying vec4 pos;
varying vec3 normal;
varying vec3 lightVec;
varying vec3 viewVec;

void main( void )
{
pos= gl_ModelViewProjectionMatrix * gl_Vertex;
normal = normalize(gl_NormalMatrix * gl_Normal);
lightVec = normalize(lpos - pos.xyz);
viewVec = vec3 (normalize(- (gl_ModelViewProjectionMatrix *gl_Vertex)));

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;
gl_TexCoord[2] = gl_TextureMatrix[0]*gl_ModelViewMatrix*gl_Vertex;
}

Fragment shader


uniform sampler2D texunit0;
uniform sampler2D texunit1;
uniform sampler2D texunit2;
uniform vec3 lpos;

varying vec4 pos;
varying vec3 normal;
varying vec3 lightVec;
varying vec3 viewVec;

void main( void )
{
gl_TexCoord[2] = gl_TexCoord[2]/gl_TexCoord[2].w;

gl_TexCoord[2]=(gl_TexCoord[2]+ 1.0) * 0.5;

vec4 base = texture2D(texunit0, gl_TexCoord[0].xy);
vec3 norm = texture2D(texunit1, gl_TexCoord[0].xy).xyz*2.0-1.0;
vec4 shadow = texture2D(texunit2,gl_TexCoord[2].xy);

norm = normalize(gl_NormalMatrix * norm);

float fresnel =max((norm.z-0.6)*-1.0,0.0);

float diffuse = max(dot(lightVec, norm),0.0);

float specular = max(dot(reflect(lightVec,norm), viewVec), 0.0)*1.7;

specular=pow(specular,8.0);

float shade=1;

if((shadow.z+0.005) < gl_TexCoord[2].z)
shade=0;
else
shade= diffuse;

gl_FragColor = (base* shade)+ (vec4(0.0,0.1,0.3,0.0)*fresnel) +(vec4(0.5,0.5,0.4,0.0)*specular*shade);
}

And that is it, shadow mapping will produce a lot of artifacts, one of them can be hidden by always including the diffuse value among the shadow.
I will continue to clear out some of them in coming tuts.

Download this tutorial for MSVCPP 6.0
note: this does not include the updated code so you need to change it before using.

Vista not!

They have been asking for it for a long time, Microsoft that is, every bad decision, every bug and every stupidity that comes out from them is about to reach a terrifying apex with the release of Vista.
So let’s bash them a little.

Now many that has seen the latest vista screen shots and listened to their propaganda might say, what’s wrong with vista, it’s more secure, has better looking graphics and so on.
True, but here is a few reasons why it’s not good.

1. WGA, or windows genuine advantage was introduced a little while ago, and it was an incredible failure, not only did it fail to correctly identify pirated copies a bit now and then, it actually gave false positives about 40% of the time with genuine copies, not exactly the intended result.
What wga did was to disallow users to upgrade their “pirated” copies (save for the most critical of upgrades) leaving them open to an avalanche of viruses, Trojans, spyware and other similar stuff, this didn’t just hurt the illegitimate users but also the legitimate ones by providing a safe harbor for that stuff, this army of zombies hurts everybody, Microsoft included.

Windows Vista will use something that can only be described as wga2, now this is supposed to be even more powerful than wga in every way, making it unable to even install or use.
Now under normal circumstances this wouldn’t be much of an problem unless we include some other factors, like the price of Vista home and the fact that pirated versions of windows make up for something like 50% of their user base, bad indeed.

2. The new user interface is another concern, now it doesn’t matter how pretty aeroglass is, if it doesn’t preform well what good is it for, both the newest Linux and mac gui’s will run on even a 32mb card like some laptops still have (aeroglass needs at least 128 MB just to run), and they sure do look (or can look) equally as good, and on top of that they preform a lot better, though i have to admit that i like the windows XP gui better than the mac one and Linux has just to many gui’s to make a quick comparison.
Now Vistas gui is directly tied to DX10, this is bad, because we all now what DX is good for, that’s right, games and only games, i have yet to find a major application (besides games) that uses DX instead of openGL.

3. Speaking of DX10, it’s a mistake to make DX10 Vista only, it’s like Microsoft expects everybody to upgrade to vista at launch day, yea right as if i am going to buy a new multi core computer with a GF8800 in SLI mode and on top of that buy a os that costs almost as much as the computer, well the first part is sort of true, but then again, will i have the money to get Vistified, i think not.
So the early adopters will be few, in fact mostly businesses will get it in the start and gamers will be the last to follow.
So what does DX10 need to get popular, that’s right, games, but gamers won’t get vista for a while, but they will get the hardware, and the only other graphics API that support the SM4 hardware is openGL, well it will support SM4 when the hardware is released, but that is still way ahead of DX10.
So you got the situation that gamers have the hardware and the drivers that support SM4 in openGL at least, but they don’t have vista and DX10 that supports SM4, the New vista users will not have the hardware or the need to get the latest games, but they will have the software for it.
Hmmmm…… i wonder what API the game developers are going to be using from now on.

4. the price from $233 to $450, but then again the $233 Vista Home Basic version is nothing to bring home, you want to spend at least $300-350 on it.
It’s a bit over the top, hell you can get a new (cheap ass) computer or a nice graphics card for just one user license, and here they are expecting rapid adoption, rapid adoption of Linux that is, you know the free os that does the same things but only more and better, it’s only fault is that is is made for better (read: geekier) people.
Then theres the fact that among Microsoft’s user base about 50% are pirated versions, and there is a reason for that, it’s not that they don’t want to spend that money, it’s because that can’t.
My sister and her BF use two computers and a mac, both with xp on them, she is still a student on maternity leave so he provides for the family, so try and justify getting genuine licenses for those computers, try justifying them upgrading both computers and getting vista on them, no Microsoft’s greed does stand in the way of that.
So if you want the expensive and gargantuan bloatware, be my guest, just don’t blame me afterwards.

So Vista is a lost cause, but hey what’s that on the horizon, could it be the next development cycle for the os after vistas successor, hey look it is. And i am going to help them on the way with a few tips and a new business model.

1. scrap the old core, make a new one or use the Linux core, i don’t care, as long as it’s super secure, lightweight, versatile and open source.

2. call what you have “Windows ****** core”, and make it free and available for download

3. make a slim graphical shell around it with only the basics, if you want you can also make a shinier aeroglass like behemoth on top of that.
Though large parts of it should be open source so people can mod it

4. call what you have “Windows ****** base”, and make it free and available for download

5. add another layer of basic applications, like notepad, a media player, a browser and so on and call it “Windows ****** home light”, this should be sold at a price you would rather find in the value bin in a game store.

Continue adding layers like this, each one adding functionality and services like a word processor, anti virus protection, document management, media downloading services and so on, the idea is to make every version of windows genuine, not by forcing everyone to buy one, but making it free or at least super cheap to get.
I do think Microsoft can live on a service model instead of the failing monopoly they have today on the OS market.

Per pixel lighting

Today we will talk about per pixel lighting, or fragment lighting as the correct term is today.
Specifically we are going to add diffuse, specular and Fresnel reflection, now it’s not normal to add the Fresnel term, but i think it’s interesting to learn and here it looks kinda good to.
This is mostly a shader tutorial since the only c++ code change from 2b is that i now load a normal texture instead of the ambocc texture (that one is baked into the diffuse texture map using photoshop), and the other thing i changed was that i now push the light position to the shader using the sendUniform3f command (lpos in the shaders), you can do it any way you want, but it is preferable to use the built in constants available, i didn’t, but that’s because i didn’t want to write more code.

Now to do fragment lighting you need some stuff from the vertex shader, specifically the position of the fragment, the vector to the viewer and the vector to the light, i have included a normal to, but since we are going to use normal mapping that will not be needed.

uniform sampler2D texunit0;
uniform sampler2D texunit1;
uniform vec3 lpos;

varying vec4 pos;
varying vec3 normal;
varying vec3 lightVec;
varying vec3 viewVec;

void main( void )
{
pos= gl_ModelViewProjectionMatrix * gl_Vertex;
normal = normalize(gl_NormalMatrix * gl_Normal);
lightVec = normalize(lpos - pos.xyz);
viewVec = vec3 (normalize(- (gl_ModelViewProjectionMatrix *gl_Vertex)));

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;
}

Now to the fragment shader, it’s a bit complex and has many parts so i will split it up a little.
First the start bit, it’s identical to the vertex shader start bit.

uniform sampler2D texunit0;
uniform sampler2D texunit1;
uniform vec3 lpos;

varying vec4 pos;
varying vec3 normal;
varying vec3 lightVec;
varying vec3 viewVec;

void main( void )
{

next we read from the textures, please note what we are doing to the normal texture, this is because, the normal texture needs to have negative values to become a normal so just multiply by two and subtract by one, simple.

vec4 base = texture2D(texunit0, gl_TexCoord[0].xy);
vec3 norm = texture2D(texunit1, gl_TexCoord[0].xy).xyz*2.0-1.0;

Next on we need to treat the normal the same way as we did the normal in the vertex shader so that as the tank rotates so does the normal.

norm = normalize(gl_NormalMatrix * norm);

After this we can begin to compute the different lighting components, first we do the Fresnel term, the Fresnel term is a value that basically controls diffuse ambient reflections at a low incandescent angle, and it looks great on round shiny objects.

float fresnel =max((norm.z-0.4)*-1.0,0);

Diffuse term is simple, it is just the dot product of the light vector and the normal.

float diffuse = dot(-lightVec, norm);

Specular is a bit more complicated, and there in no real correct way of doing this, specular highlights are basically a diffuse reflection of the light source.

float specular = max(dot(reflect(-lightVec,norm), viewVec), 0.0)*1.1;
specular=pow(specular,8.0);

and finally we bring it all together

gl_FragColor = (base * diffuse) +(vec4(0.0,0.5,1,0.0)*fresnel) +(vec4(1.0,1.0,0.8,0.0)*specular);

}

Download this tutorial for MSVCPP 6.0

Textures and shaders

This tutorial will be short, basically we are going to add texturing to the shader equation.
So what do we need for this one.
First we need to be able to send uniforms to the shaders, now uniforms are constants that you set and they can control many different aspects of the shader, however unlike the varying variables these variables will not interpolate across the polygons.
In this tut we will use them to send the sampler cords which is sort of stupid since it’s just a number like 0 or 1, but it has to be done.
I will use this function for this job, i got several more of these for other types of variables included in the code.

void sendUniform1i(char var[60], int v)
{
GLint loc = glGetUniformLocationARB(ProgramObject, var);
if (loc==-1) return; // can't find variable

glUniform1iARB(loc, v);
}

Then we need to load textures, fortunately i added a load texture function, it’s a nifty little thing, ok it’s a jumbled mess of crappy code, but it does work, most of the time.
Anyway any texture loading function will do it’s no biggie, i load the textures like this.

tex1=LoadGLTextures("cv90base",2);
tex2=LoadGLTextures("cv90ambientocc",2);

The “2″ tells the loader to use trilinear filtering with ansitopic filtering.

Next up is the multi texturing code, it’s par of the rendering code so just let’s see it all at once.


if (useshader) glUseProgramObjectARB(ProgramObject);
sendUniform1i("texunit0", 0);
sendUniform1i("texunit1", 1);

glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,tex1);

glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,tex2);

cv90_render();

glActiveTextureARB(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
glActiveTextureARB(GL_TEXTURE0);
glDisable(GL_TEXTURE_2D);
if (useshader) glUseProgramObjectARB(0);

Finally the shader code itself (we only change the fragment shader code)

uniform sampler2D texunit0;
uniform sampler2D texunit1;
varying vec4 pos;

void main( void )
{

vec4 base = texture2D(texunit0, gl_TexCoord[0].xy);
vec4 ambi = texture2D(texunit1, gl_TexCoord[0].xy);

gl_FragColor = base * ambi;
}

This shader reads from booth textures and then multiplies them together, simple as always, the next one will be more complicated as we add ppl lighting, wohoo.
Download this tutorial for MSVCPP 6.0

WordPress Themes