XNA changing blendstate from alpha to Additive - c#

Here's my problem
I am using a depth control but now i have different sprites that need different blendstates
how can i change this if I already started the spritebatch.begin(...)
I was trying to change spritebatch.graphicsDevice.blendstate but it doesn't seems to be working
I cannot turn a black area into transparency
Thank you
Still seems it cannot save the layer order between them by using that code...
I guess the problem might be in using object.draw(spritebatch) and then draw inside the method.
I think theres a problem because i have 2 classes each one with a draw method with input spritebatch
this is what im doing
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.Additive);
d.drawAttack(gameTime, spriteBatch);
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
drawObjects(gameTime, spriteBatch);
charactersDraw(gameTime, spriteBatch); // same class as the d.drawAttack
spriteBatch.End();
they both draw but the layer !BETWEEN both spritebatche! doesn't seems to make any difference
the layerdepth works fine with characters and draw objects... only doesn't work with drawAttack

You need to do multiple SpriteBatch.Begin() .. End() calls, each with a different BlendState. You can still preserve your layerDepth among them.
For example:
batch.Begin(SpriteSortMode.FrontToBack, BlendState.Additive);
batch.Draw(tex1, sprite1, null, Color.White, 0.0f, Vector2.Zero, 1.0f,
SpriteEffects.None, layer1);
batch.Draw(tex2, sprite2, null, Color.White, 0.0f, Vector2.Zero, 1.0f,
SpriteEffects.None, layer2);
batch.End();
//new blend state, new begin...end
batch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
batch.Draw(tex3, sprite3, null, Color.White, 0.0f, Vector2.Zero, 1.0f,
SpriteEffects.None, layer3);
batch.Draw(tex4, sprite4, null, Color.White, 0.0f, Vector2.Zero, 1.0f,
SpriteEffects.None, layer4);
batch.End();

Related

How do I stop a texture from darkening after drawing a colored quad in C# OpenTK?

I am creating my own game graphics engine. I have looked into using others like Unity, but they don't fit my needs. Anyway, I am using OpenTK (This is a 2D game), and the issue is that when i draw a texture to the screen, then draw a quad to the screen, the color darkens on the texture. Here is the method I am using to draw a texture:
public void Texture(int ID, Vector2 size, Vector2 pos, Vector2 texSize, Vector2 texPos)
{
pos.Y = -pos.Y;
GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, ID);
GL.Begin(PrimitiveType.Quads);
GL.TexCoord2(texPos.X, texPos.Y);
GL.Vertex2(pos.X, pos.Y);
GL.TexCoord2(texPos.X + texSize.X, texPos.Y);
GL.Vertex2(pos.X + size.X, pos.Y);
GL.TexCoord2(texPos.X + texSize.X, texPos.Y + texSize.Y);
GL.Vertex2(pos.X + size.X, pos.Y - size.Y);
GL.TexCoord2(texPos.X, texPos.Y + texSize.Y);
GL.Vertex2(pos.X, pos.Y - size.Y);
GL.End();
}
I am inverting the Y because I am used to the Windows Forms coordinate system, where going down is y++. I am calling it like this:
Texture(backdropTextureID, new Vector2(1f, 1f), new Vector2(-0.5f, -0.5f), new Vector2(1f, 1f), new Vector2(0f, 0f));
As expected, if there is nothing else being drawn, it draws a texture with the GL id of backdropTextureID in the center of the screen. When I draw a colored quad also though, the texture is darkened. Here is the method I am using for drawing a quad:
public void Quad(Vector2 pos1, Vector2 pos2, Vector2 pos3, Vector2 pos4, Color color1, Color color2, Color color3, Color color4)
{
GL.Disable(EnableCap.Texture2D);
pos1.Y = -pos1.Y;
pos2.Y = -pos2.Y;
pos3.Y = -pos3.Y;
pos4.Y = -pos4.Y;
GL.Begin(PrimitiveType.Quads);
GL.Color3(color1);
GL.Vertex2(pos1);
GL.Color3(color2);
GL.Vertex2(pos2);
GL.Color3(color3);
GL.Vertex2(pos3);
GL.Color3(color4);
GL.Vertex2(pos4);
GL.End();
}
Again, inverting the Y, for the reason stated above. Also, notice, I am enabling EnableCap.Texture2D in the method for drawing a texture, and disabling it when I draw a colored quad. I am calling the quad method like this:
Quad(new Vector2(0.0f, 0.0f), new Vector2(0.5f, 0.0f), new Vector2(0.5f, 0.5f), new Vector2(0.0f, 0.5f), Color.Gray, Color.Gray, Color.Gray, Color.Gray);
If anyone could help me, thank you in advance. Basically: How do I stop a texture from darkening after drawing a colored quad in C# OpenTK?
For anyone whose having this problem, I figured it out. The same color I was giving to the colored quad i gave to the texture. You just need to add
GL.Color3(Color.Transparent);
to the start of the texture drawing method.

Rotate 2D texture XNA

I'm trying to rotate my shot Texture by 180 degress, but when I do the following:
spriteBatch.Draw(TexTiro, Position, null, Color.White, (float)(180), new Vector2(), Vector2.One, SpriteEffects.None, 0f);
the texture appears like this:
What am I doing wrong?
It is because the rotation is in radians.
You can use MathHelper.ToRadians() to easily convert degrees to radians: see here
spriteBatch.Draw(TexTiro, Position, null, Color.White, MathHelper.ToRadians(180), new Vector2(), Vector2.One, SpriteEffects.None, 0f);
In XNA the unit is radians not degrees. so 180 would be (float)Math.PI

Drawing upscaled image with no smoothing

I want to draw a texture2d 5 times larger than original with no smoothing.
Drawing line:
spriteBatch.Draw(texture, new Vector2(0, 0), null, Color.White, 0, Vector2.Zero,
5f, SpriteEffects.None, 0);
The result is a scaled smoothed image. Adding this.GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp; doesn't help.
What you want is Point Texture filtering. Look here.

How can I create a drop shadow effect on my textures in XNA for Windows Phone?

I'm writing a simple 2D game for Windows Phone 7 using the XNA Framework.
Basically there are multiple items that the user can drag. I create their texture dynamically by drawing stuff on a RenderTarget2D and then just draw the RenderTarget2D afterwards. I use the stencil buffer to draw a part of a bigger texture onto the render target.
Code snippet
util.GraphicsDevice.SetRenderTarget(result);
util.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.Stencil | ClearOptions.DepthBuffer, Color.Transparent, 0, 0);
// The "mask"
spriteBatch.Begin(SpriteSortMode.Deferred, util.DontWriteColorsState, null, util.StencilAlways, null, alphaTestEffect);
spriteBatch.Draw(maskTexture, destination, Color.White);
spriteBatch.End();
// The actual texture
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, util.StencilKeepWhere1, null, alphaTestEffect);
spriteBatch.Draw(bigTexture, destination, source, Color.White);
spriteBatch.End();
util.GraphicsDevice.SetRenderTarget(null);
(util is just an instance of a helper class which I use in order to not have to copy-paste the same code everywhere, it contains the DepthStencilState objects and some other stuff.)
I would like to create a drop shadow effect behind these textures. I'd like to draw the shadow on the render target.
Unfortunately Windows Phone 7 doesn't support custom shader effects so I can't use any examples from the internet. So I decided to try to implement it in software. But I'm completely inexperienced with this kind of thing, so the result was both slow and ugly.
What I did in software was this:
Created a stroke around the mask texture and drew it with a low opacity
Created a stroke around the previous stroke and drew it with a low opacity
... This step was repeated the same number of times as the size of the drop shadow
However, it was VERY slow and basically unacceptably slow.
So the question is
Is it possible to create a dropshadow or a dropshadow-ish effect using the built-in effects in XNA? Also, if not, is there an algorithm that can create a nice-looking drop shadow in software?
Thanks in advance for your answers! :)
EDIT:
I'm taking about this kind of drop shadow:
Obviously, this is just an illustration, I don't want it to be exactly this size. :)
I took the liberty of adjusting your solution, #Venemo, and here is what I've come up with as a good start:
public Texture2D CreateBlurredTexture(Texture2D originalTexture, SpriteEffects effects)
{
var device = originalTexture.GraphicsDevice;
var rt = new RenderTarget2D(device, originalTexture.Width/2, originalTexture.Height/2);
var rt2 = new RenderTarget2D(device, originalTexture.Width, originalTexture.Height);
Color shadowColor = Color.Lerp(Color.Black, Color.Transparent, 0.9f);
using (var spriteBatch = new SpriteBatch(device))
{
device.SetRenderTarget(rt);
device.Clear(Color.Transparent);
spriteBatch.Begin();
spriteBatch.Draw(originalTexture, new Rectangle(0, 0, rt.Width, rt.Height), null, shadowColor, 0, Vector2.Zero, effects, 0f);
spriteBatch.Draw(originalTexture, new Rectangle(1, 1, rt.Width - 2, rt.Height - 2), null, shadowColor, 0, Vector2.Zero, effects, 0f);
spriteBatch.Draw(originalTexture, new Rectangle(2, 2, rt.Width - 4, rt.Height - 4), null, shadowColor, 0, Vector2.Zero, effects, 0f);
spriteBatch.Draw(originalTexture, new Rectangle(3, 3, rt.Width - 6, rt.Height - 6), null, shadowColor, 0, Vector2.Zero, effects, 0f);
spriteBatch.Draw(originalTexture, new Rectangle(4, 4, rt.Width - 8, rt.Height - 8), null, shadowColor, 0, Vector2.Zero, effects, 0f);
spriteBatch.End();
device.SetRenderTarget(rt2);
device.Clear(Color.Transparent);
spriteBatch.Begin();
spriteBatch.Draw(rt, new Rectangle(0, 0, rt2.Width, rt2.Height), Color.White);
spriteBatch.End();
device.SetRenderTarget(null);
}
return rt2;
}
What it does is creates copies of the texture and adds opacity with each draw, while going towards the center. After this is done, you can offset it and increase its size to create a bigger shadow effect. This should accomplish the task depending on your texture.
To draw a shadow draw the original render target in pure black, maybe with some transparency, offset slightly from the original position.
Next just draw again, as you were before to render the texture over the shadow.
Regarding your edit, create a texture for an edge and a texture for a corner, then draw the drop shadow as 4 edges and 4 corners.
This is what I came up with, eventually.
It is a bit hacky, of course but it sort of does what I needed when I asked the question.
public static Texture2D CreateBlurredTexture(Texture2D originalTexture, SpriteEffects effects)
{
var device = originalTexture.GraphicsDevice;
var rt4 = new RenderTarget2D(device, originalTexture.Width / 4, originalTexture.Height / 4);
using (var rt2 = new RenderTarget2D(device, originalTexture.Width * 3 / 2, originalTexture.Height * 3 / 2))
using (var rt3 = new RenderTarget2D(device, originalTexture.Width / 2, originalTexture.Height / 2))
using (var spriteBatch = new SpriteBatch(device))
{
device.SetRenderTarget(rt2);
device.Clear(Color.Transparent);
spriteBatch.Begin();
spriteBatch.Draw(originalTexture, new Rectangle(0, 0, rt2.Width, rt2.Height), null, Color.White, 0, Vector2.Zero, effects, 0f);
spriteBatch.End();
device.SetRenderTarget(rt3);
device.Clear(Color.Transparent);
spriteBatch.Begin();
spriteBatch.Draw(rt2, new Rectangle(0, 0, rt3.Width, rt3.Height), Color.White);
spriteBatch.End();
device.SetRenderTarget(rt4);
device.Clear(Color.Transparent);
spriteBatch.Begin();
spriteBatch.Draw(rt3, new Rectangle(0, 0, rt4.Width, rt4.Height), Color.White);
spriteBatch.End();
device.SetRenderTarget(null);
}
return rt4;
}

Managed DirectX: Specifying the Depth (Z-Order) of Sprites containing Texture and Text

I am using managed DirectX to try and draw a texture and a piece of text to the screen using a Sprite. Unfortunately, if I place the text and the texture in the same sprite, the texture overwrites (overdraws?) the text regardless of the order I do the draw commands.
Since I will eventually want to intersperse textures and text, how do I specify a Z-order for these sprites. Does each layer have to be in a separate sprite?
Here is the current code:
m_device.BeginScene();
m_device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0);
m_sprite.Begin(SpriteFlags.SortTexture | SpriteFlags.AlphaBlend);
// Switching the order of following two statements doesn't change the Z-Order!
m_sprite.Draw(m_texture, Vector3.Empty, new Vector3(0, 0, 0),
Color.White.ToArgb());
m_d3dFont.DrawText(m_sprite, m_text, x, y, color);
m_sprite.End();
m_device.EndScene();
m_device.Present();
Note: Using the SpriteFlags.SortDepthBackToFront or SpriteFlags.SortDepthBackToFront does not change the behaviour.
This is probably a conceptual misunderstanding on my part, but if code is useful, I'll gratefully accept samples in unmanaged DirectX using C++ or whatever language.
Many thanks in advance!
If you want to change the Z-Order of rendering then you have to set the Z value in the Draw command. If you set the all to 0 you will get all sorts of weirdness. Your bigger issue is that DrawText doesn't allow you to set a Z-Depth which is all kinds of rubbish.
Thus your only chance is to use ID3DXSprite::SetTransform. You need to shift only the Z-Coordinate back with it for the relevant z ordering position. So you can set your transforms (assuming you are using identity world matrices) as follows (C++ example)
D3DXMATRIX mat( 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, zOrder, 1.0f );
m_Sprite->SetTransform( &mat );
You then carry on passing a position of (0, 0, 0) for rendering and text will also gain the correct depth for z-ordering.
Hope that helps.
Here is the answer I (the poster) went with:
Goz provided most of the information needed to solve the problem. Essentially, for textures, you can specify the z-order using the third parameter of the second Verctor3. Experimentation has made it clear that (1) z order goes from 0.0 to 1.0, with 0.0 being closest and 1.0 being the the furthest away. Anything out of that range doesn't appear at all.
For text, because there's no opportunity to specify the z in the call, you need to use Goz's suggestion of a transform matrix.
In the end, here's roughly the code I used.
m_device.BeginScene();
m_device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0);
m_sprite.Begin(SpriteFlags.SortDepthFrontToBack | SpriteFlags.SortTexture | SpriteFlags.AlphaBlend);
// The "1.0f" is the z-order of texture1. This places it at the very back.
m_sprite.Draw(m_texture1, Vector3.Empty, new Vector3(0, 0, 1.0f),
Color.White.ToArgb());
// The text1 is placed at z-order 0.8f, in order to place it in front of texture1
Microsoft.DirectX.Matrix t = Microsoft.DirectX.Matrix.Identity;
t.Translate(new Vector3(0, 0, 0.8f));
m_sprite.Transform = t;
m_d3dFont.DrawText(m_sprite, m_text1, 200, 200, color1);
m_sprite.Transform = Microsoft.DirectX.Matrix.Identity;
// The "0.6f" is the z-order of texture2. This places it at the very back.
m_sprite.Draw(m_texture2, Vector3.Empty, new Vector3(220, 220, 0.6f),
Color.White.ToArgb());
// The text2 is placed at z-order 0.4f, in order to place it in front of texture2
t = Microsoft.DirectX.Matrix.Identity;
t.Translate(new Vector3(0, 0, 0.4f));
m_sprite.Transform = t;
m_d3dFont.DrawText(m_sprite, m_text2, 240, 240, color2);
m_sprite.Transform = Microsoft.DirectX.Matrix.Identity;
m_sprite.End();
m_device.EndScene();
m_device.Present();

Categories