Archive for April, 2009

Bloom

Wednesday, April 29th, 2009

After a long week of rest, I went to the sea at HuaHin with my friends, then went back to see my mom.
All about rest and relax.

Now back to business, I have gotten my hand dirty again.

I have looked into the bloom post-processing sample from creator club. Not long that I decide to do some post-processing to enhance my scene. And that pretty result comes from the game I played along a week ago, it’s “Elder Scrolls IV: Oblivion”.

All the shinny thing and burn-out stuff just enough get me to this.

The sample from creator club just explain clearly enough for me to go on.
To do the bloom post-processing, you need to render the scene multiple times based on the step and passes of your algorithm too. For the sample case, it uses 4 passes, see the following

Pass 1: Render the scene with the lower-than bright threshold value excluded.
Pass 2-3: Render the scene from pass 1 but apply it with blur effect. No matter your blur algorithm is, you just need to blur it. (The sample use Gaussian Blur algorithm separately for vertical and horizontal, thus we can count for this 2 passes.)
Pass 4: Combine the original scene with the result from pass: 2-3.

Now you will have more shinny effect with the brighter area coming all around.

Let’s see the actual shader code implement for this. (Most of them come from the sample itself, but you know I dont want to just copy and paste it, I want to understand the concept and reason of usage behind, so you can adapt and do more with them ;)

Following is the effect that I have apply, pass by pass,

BloomExtract

float4 PixelShader(float2 texCoord : TEXCOORD0) : COLOR0
{
	//look up the color from the texture
	float4 color = tex2D(sceneSampler, texCoord);
 
	//extract the bright pixel (only those that higher than BloomThreshold will still hold)
	return saturate( (color - BloomThreshold) / (1 - BloomThreshold) );
}

If we want to exclude out the “not enough bright pixel” then look at the line

saturate( (color - BloomThreshold) / (1 - BloomThreshold) )

This will cut out the below threshold value and recalculate from the whole less.

BloomBlur

//Width to sampling-pixels
float blurMag;
 
//Alpha value
float alpha;
 
const float2 offsets[12] = {
   -0.326212, -0.405805,
   -0.840144, -0.073580,
   -0.695914,  0.457137,
   -0.203345,  0.620716,
    0.962340, -0.194983,
    0.473434, -0.480026,
    0.519456,  0.767022,
    0.185461, -0.893124,
    0.507431,  0.064425,
    0.896420,  0.412458,
   -0.321940, -0.932615,
   -0.791559, -0.597705,
};
 
float4 PixelShader(float2 texCoord : TEXCOORD0) : COLOR0
{
	//look up the color from the texture
	float4 sum = tex2D(sceneSampler, texCoord);
 
	//accumulate from the 12-kernel
	for(int i=0; i<12; i++)
	{
		sum += tex2D(sceneSampler, texCoord + blurMag * offsets[i]);
	}
 
	//average them
	sum /= 13;
 
	return sum;
}

You see the offsets array with the 12 of 2 space coordinate inside it, it will be the displacement offseter for us. (Note that this blur I used is different from the one use in the creator sample).

What we gonna do here is, for each pixel we will calculate the 12-neighbor pixels’ color and sum it, then average, after that we get the color that should be represent for individual pixel we working on.
By offset the texture’s color sampling from the offsets array, multiply it with the default texture’s coordinate.

Note: I think the value inside the offsets array can be arbitrary set, but I have not test it yet. So you have the opportunity to test it.

By changing from 12-pixel to higher number, you will get more and more blur result and more accurate, but if the number of pixels is more than enough then you may get the same color representing that individual pixel, thus it means that by setting the number of pixel to 30 you may get the same result at 60 (this comes from my bit of theory ).

CombineFinal
This one will combine the result from the blur pass(already extracted), with the original scene.
The theory comes to play again, as you can see in the creator club sample, it said that human’s eye is sensitive to green light, more than blue light, thus we will lerp the color for this pass too.

// Helper for modifying the saturation of a color.
float4 AdjustSaturation(float4 color, float saturation)
{
    // The constants 0.3, 0.59, and 0.11 are chosen because the
    // human eye is more sensitive to green light, and less to blue.
    float grey = dot(color, float3(0.3, 0.59, 0.11));
 
    return lerp(grey, color, saturation);
}
 
float4 PixelShader(float2 texCoord: TEXCOORD): COLOR0
{
	float4 scene = tex2D(sceneSampler, texCoord);
	float4 bloom = tex2D(postSampler, texCoord);
 
	//adjust color saturation and intensity
	scene = AdjustSaturation(scene, sceneSaturation) * sceneIntensity;
	bloom = AdjustSaturation(bloom, bloomSaturation) * bloomIntensity;
 
	//darken the scene image where there is a lot of bloom
	//this will avoid the too much of burn-out effect
	scene *= (1 - (saturate(bloom)-0.0001));
 
	return scene + bloom;
}

You also see the saturation value for both scene, and bloom part, and also the intensity for both of them.
By having these variables, we can change the effect-looking of the scene to various way => like burn-out, stable, or more and more shinny.

See the line,

scene *= (1 - (saturate(bloom)-0.0001));

it means that we will lower the brightness of color of the scene as always, this will let the bloom more takes into effect. If there is alot of bloom then the more we will lower the original scene. Also I subtract (bias) with the value of 0.0001, in the case where saturate(bloom) equals to 1, i dont want the original scen color to just disappear.

We are there anyway. Doing the post-processing is fun to play.
I have some images below to show to you too.
It looks similar to the one from Catalin Zima at Ziggyware, because I have used the same models and his deferred shading method.
And also the algorithm of shader is more the same as the one from creator but I recoded in my own way (just to learn), as you can see I have change the blur algorithm to another one that easier (adapt a little bit from Jamezila by cut out the bloom part but remain only the blur part.)

Okay, enough talk already, below is the images,

Until next time.

[Thanks for Catalin Zima for his great deferred shading, Jamezila for very simple but wonderful bloom/blur effect, Creator Club for great tutorial sample and models-usage.]

Watercity enhanced (again) with fog

Wednesday, April 15th, 2009

Wow, quite alot of enhancement for me though.
This time I up for even another level, with the adding of fog to the watercity scene, and you can setting the fog’s properties in real-time.

It’s quite nice.
Of course, you can download my project file at the bottom to learn it by yourself.
Enjoy!!

Download the project file here: winformsoptimized.

Watercity in winform (tool-creation example)

Tuesday, April 14th, 2009

I up the level of the previous watercity into another step.
By integrated it with the winform. In this way you can create the tool-set for your 3d-app, game, and whatever you can imagine. With the flexibility from the serveral controls in windows programming, you can add many and many options to change your 3d app’s settings.

Personally I like to do with this way, integrating with winform can greatly higher the app’s usefulness.
Beside the good thing, while you are developing and integrating your xna app with the winform, I have found some annoys, it’s the design mode that usually erases my custom control’s code, so I have to recode it again and again.
I don’t know how to fix it. But my solution is this, “try to put your custom control to the main form at last step”, this way you should really get going with your project. If you can’t find that problem, maybe you can tell me that too ;)

Another thing to keep in mind that, this project is not optimized yet, the framerate I have gotten so far is far from what is called ‘good performance’, you have to try to set some winform’s settings to reach that peak, there must be some ways to workaroud this because I get very framerate from my normal fullscreen xna compared to this one.
I have posted this question on xna creators club already, if I found that solution I will tell you later.

Below you can see the example screenshot from my tool, it’s the watercity scene along with some settings at the right.
You can download the full project from the link below too.

Note: I have created it with Visual Studio C# Express 2008, with the XNA Framework 3.0.

Download project file:  watercityinwinforms

Watercity

Sunday, April 12th, 2009

Now, I quite finished my testbed on water.
I named it “Watercity”.

Please enjoy!!

Water reflection testbed (working gallery)

Saturday, April 11th, 2009

I want to show some of my screenshots taken from the recent testbed on “Water reflection”, from the ground up, it includes the diffuse texturing, specular texturing, specular highlighting, reflection, and ripple (or perturbation texturing).

Below you will find the screenshots from the start of the testbed’s process.

I am so sorry that I cannot include any in-depth detail here, due to I have no time at all right now. So I decide to post my progress in screenshots instead. If you visit my blog site, you will find that most of the posts are about the showcase.

But I can give you brief detail about all of this.
In order to do the more realistic (at least close enough to realistic) reflection water on the floor, road or anything shinny. You have to create the reflection plane first, then draw the reflected scene into it. In which case, you can blend it with the prior floor below it as I did here. You should set the appropriate renderstate correctly to give you out the most realistic scene (also consider performance.).

After that,  you add more realistic effect, to make it looks more like the water. It’s the ripples, or technically called “perturbation of texture”. This case, you need a bump map, to represent your randomness of the way the reflected scene you drawed will look like. In this case, the bump map is the water’s wave, it represents the flatness of each pixel in the water in which you drawed it into the reflected plane recently.

Finally, you come close to the natural look of water. Note that I am not don’t yet with the “fresnel term”. In which it will need one more texture to be added its color with, it’s refraction map.

Afterall, enjoys the following gallery.!