📜 ⬆️ ⬇️

XNA Draw: improving the graphics of the game



Hello.

All my eight articles on Habré are articles about game devs, most of them are related to such a wonderful framework as XNA. The first acquaintance with XNA was an article about creating a musical toy , then the complexity of the articles was increasing, I started writing about particle systems , and then about shaders and more shaders .
')
In general - on the shaders I wanted to finish, however, to cost a bit to complement them, I will talk about several algorithms for improving the graphics in the game. Examples of improvements:



If interested - under habrakat.

Introduction


We will touch again on the 2D component of games and will work only with pixel shaders.

This article will be slightly different from my other, here will immediately go and theory and practice, it is implied that you have already read articles about shaders here and here .

Consider all the effects that were used in the game and a couple of effects that were not there, the video is quite old, and the game has already suffered qualitative changes since.

Distortion


The very first effect that catches your eye is distortion:


This effect is not handled by a special shader, in general, it is the same as in the article I wrote earlier.

Let's take that explosion effect.

The following textures are used here:


In the upper left corner - the texture of smoke, smoke forms a "ring" around the explosion, a bright area in the explosion, which quickly goes out and the plume from the rocket. This is the main texture of this effect. Used as a visible texture and distorting texture.

Next - a point near the smoke, thanks to her - there are lightning that emanate from the center of the explosion. It is also used as a visible texture and distorting texture.

Well, for extra beauty - particles from the explosion, the biggest texture on the strip. But here it is worth noting that the player will never see it directly. It is distorting and quickly disappears.

PS a couple of tips for beginners making a particle system:


HUD Distortion (interface distortion)



The second effect that could have been noticed in the video is the distortion of the interface.
I was inspired by games like Crysis 2 and Deus Ex: Human revolution . There, with the death - the interfaces began to be distorted in various ways. It seemed to me interesting. Also, I strengthened the interface distortions with a simple hit.

For example, the death of a player:


This shader is very similar to the one that was before - image distortion. However, the root is different from it. The distortions do not come from the distortion map, but from mathematical formulas, let's consider the shader code (the shader is as simple as possible to understand):

float force; //  ""  float timer; //  ,   . float random1; //   float random2; //   float initialization; //   ""  float desaturation_float; //    sampler TextureSampler : register(s0); float4 main(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0 { texCoord.y += cos(texCoord.x) * timer * 0.0002f * force; //  if(initialization > 0) { texCoord.x += cos(texCoord.y) * initialization; //  } if(texCoord.y > random1 && texCoord.y < random2) //  { float moving = force; if(timer > 100) moving *= -1.0; texCoord.x += timer / 5000.0 * moving * random2; color *= 1 + random2 * force; } if(timer < 20 && force > 0.3) //   { color.b = random2; color.g = random1; } if(timer > 50) //  "" { color *= 1 + random1/3 * (1 + force); } float4 source = tex2D(TextureSampler, texCoord); float4 sourceR = tex2D(TextureSampler, texCoord + float2(0.01*force*random1, 0)); sourceR.g = 0; sourceR.b = 0; float4 sourceB = tex2D(TextureSampler, texCoord - float2(0.01*force*force*random2, 0)); sourceB.r = 0; sourceB.g = 0; float4 sourceG = tex2D(TextureSampler, texCoord - float2(0.01*force*((random1+random2) / 2), 0)); sourceG.r = 0; sourceG.b = 0; float4 output = (sourceR+sourceB+sourceG); output.a = source.a; float greyscale = dot(output.rgb, float3(0.3, 0.59, 0.11)); output.rgb = lerp(greyscale, output.rgb, 1.0 - desaturation_float); return color * output; } technique HUDDisplacer { pass DefaultPass { PixelShader = compile ps_2_0 main(); } } 


The code is quite simple, and the result of the shader itself looks impressive.

Static texture to dynamic texture



Creating "live" textures from less alive. For example, few people noticed - the twinkling of distant stars in the video above. Although, the texture itself is static.

Consider this shader:

 float modifer; //   sampler TextureSampler : register(s0); float4 main(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0 { float4 output = tex2D(TextureSampler, texCoord); float greyscale = dot(output.rgb, float3(0.3, 0.59, 0.11)); if(greyscale > 0.2) { color *= 1 + (modifer*greyscale / 1.5); if(greyscale > 0.8) { color *= 1 + (modifer*2); } } return color * output; } technique BackgroundShader { pass DefaultPass { PixelShader = compile ps_2_0 main(); } } 


If the pixel brightness ( grayscale ) is more than 20% - a slight flicker is created, if more than 80% - strong.
The picture of this can not be shown, everything can be seen in the video.

Well, consider two more effects, which are not in the video and they are implemented in newer versions.

Bloom (glow effect)



The glow effect is familiar to everyone, also referred to as Bloom .
The idea is simple, extract bright areas from an image (some threshold is entered), then draw our scene and above the blurred scene. Bright areas begin to glow.

Examples in pictures:
Scene brightness:


Original scene:


Finished scene:


Consider the shader code, it consists of two parts, a shader that extracts the brightness and a shader that forms the final image.
Listing shader that extracts brightness:

 sampler TextureSampler : register(s0); float4 main(float2 texCoord : TEXCOORD0) : COLOR0 { float4 c = tex2D(TextureSampler, texCoord); float BloomThreshold = 0.1; return saturate((c - BloomThreshold) / (1 - BloomThreshold)); } technique ThresholdEffect { pass DefaultPass { PixelShader = compile ps_2_0 main(); } } 


Listing the shader, which gives the final result:

 texture bloomMap; sampler TextureSampler : register(s0); sampler BloomSampler : samplerState { Texture = bloomMap; MinFilter = Linear; MagFilter = Linear; AddressU = Clamp; AddressV = Clamp; }; // -  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 AdjustSaturation(float4 color, float saturation) { float grey = dot(color, float3(0.3, 0.59, 0.11)); return lerp(grey, color, saturation); } float4 main(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0 { float BlurPower = 0.01; // 0.01 float BaseIntensity = 1; float BloomIntensity = 0.4; // 0.4 float BaseSaturation = 1; float BloomSaturation = 1; float4 original = tex2D(TextureSampler, texCoord); //  float4 sum = tex2D(BloomSampler, texCoord); for(int i = 0; i < 12; i++){ sum += tex2D(BloomSampler, texCoord + BlurPower * offsets[i]); } sum /= 13; original = AdjustSaturation(original, BaseSaturation) * BaseIntensity; sum = AdjustSaturation(sum, BloomSaturation) * BloomIntensity; return sum + original; } technique BloomEffect { pass DefaultPass { PixelShader = compile ps_2_0 main(); } } 


Motion blur


Well, the last effect, this motion blur (in conjunction with other effects) gives them a “softness”, sharply moving the mouse and:



It is implemented too, quite simply:
 float rad = direction_move.x; float xOffset = cos(rad); float yOffset = sin(rad); for(int idx=0; idx<15; idx++) { texCoord.x = texCoord.x - 0.001 * xOffset * direction_move.y; texCoord.y = texCoord.y - 0.001 * yOffset * direction_move.y; c += tex2D(TextureSampler, texCoord); } c /= 15; 


Where direction_move is a motion vector.

Conclusion



With the help of such things here - you can give your game a big "highlight", and such things are done quite simply.

At this, I think, the “course” in 2D games is over, after a while - I will start writing about creating three-dimensional games.

PS the creation of this game (the one in the video) - most likely will remain at this stage. I do not have enough resources (time, enthusiasm, inspiration), to work on such a big project alone is suicide.

PSS is a huge request to write me a personal message about ochepyatka / errors, do not write comments without useful semantic meaning.

PSSS will be glad to new contacts ;-)

I wish you success!

Source: https://habr.com/ru/post/147799/


All Articles