Drawing textures with variable transparency - c#

I am a moderately experienced C# developer, but I'm new to XNA and graphics in general. I'm making a 2D game and I'm trying to draw a texture that partially transparent. The desired transparency value is stored in a float variable. The only solution I've found is to directly edit the alpha values in the texture each frame, but that seems inefficient. I've tried using alpha blending, but I haven't been able to figure out how to use my own transparency value. Is there a better way to do it?
Edit: Added more information.

if you are using spritebatch is easy:
float alpha = desired_alpha;
spritebatch.Draw(texture, pos, source, Color.White * alpha);

You could try using this Color constructor to pass in your alpha value:
http://msdn.microsoft.com/en-us/library/dd231957(v=xnagamestudio.31).aspx

Related

Don't tint, but "Colorize" sprite

In my 2D tile based game, the player can paint tiles to change there color. The simple approach (and what I have already done) is to use the tint parameter in SpriteBatch.Draw.
This looks nice, and here is an example:
But say, I want to paint the wood white. If you have ever messed with the tint, you know this isn't possible using the tint parameter. Color.White will tint the sprite the default color, and not white. This isn't a major problem, but I suppose some users might want it.
My question is, is there a method to color a sprite based on hue/saturation instead of tint. Similar to the "colorify" function in GIMP.
An obvious approach would to be to use this function in GIMP and just export sprites for each color. The trouble comes in at the fact that this would take forever to do for all my sprites, and each sprite has multiple variations, meaning you could have in total 100+ combos for one block type.
Is this possible? I suppose a shader might get the job done.
The "colourify" function in The GIMP simply does a desaturate (convert to grayscale), followed by a colour multiplication. Very simple. This should be the equivalent HLSL (untested):
float4 original = tex2d(...);
float q = (original.r + original.g + original.b) / 3;
q /= original.a; // optional - undo alpha premultiplication
return float4(tint.rgb * q, tint.a * original.a);
But you could achieve the same effect by simply storing all your textures desaturated to begin with and using the default SpriteBatch shader for its multiplication. If you don't want to modify your source art, you could do it in a custom content processor.
Although, if you want to use a custom shader, you can do something more sophisticated. You could implement a full hue-rotation (kinda complex). But perhaps you could consider something like the "Overlay" blend mode (very simple) - which lets you colourize the grays, while preserving both the highlights and lowlights (instead of multiply, which also colourizes the highlights).
To continue using the tint in SPriteBatch.Draw. Just make your "paintable" textures grayscale. So the white wood would be your default, but you draw it with a tint that makes it wood-colored.
I often use this to make UI and team coloring :)
in case it is interesting, what the tint does is just to multiply each pixel in the texture by the color you choose.
example:
texture pixel is (rgba) [1.0, 0.5, 0.5, 1.0]
tint is [1.0, 0.5, 0.5, 0.5]
result is [1.0, 0.25, 0.25, 0.5] (half transparent and more red-ish)

Billboard Transparency in XNA for Windows Phone

Okay so hopefully a simple fix that I'm just not seeing: I'm trying to implement transparency on a Billboard for an explosion, however the sprite stays solid where there is a pixel not defined transparent in the png file itself. I'm trying to change the transparency by multiplying Color.White by the transparency (a float between the value of 0 and 1)
spriteBatch.Begin(0, BlendState.NonPremultiplied, null, DepthStencilState.DepthRead, RasterizerState.CullNone, basicEffect);
Vector3 viewSpaceTextPosition = Vector3.Transform(this.position, camera.View * invertY);
spriteBatch.Draw(Texture, new Vector2(viewSpaceTextPosition.X, viewSpaceTextPosition.Y), null, Color.White * this.Transparency /*Here's where I try to set the transparency of the image drawn*/, 0, new Vector2(Texture.Bounds.Center.X, Texture.Bounds.Center.Y), this.Scale, SpriteEffects.None, viewSpaceTextPosition.Z);
spriteBatch.End();
Are there any obvious mistakes? Or is XNA for Windows Phone 7 just incapable of rendering transparent things in 3D?
Since you're using BasicEffect instead of the built-in sprite effect, I'm pretty sure you need to set the material alpha:
basicEffect.Alpha = this.Transparency;

Resizing a Texture2D without Draw

As the title states, I'm trying to resize a Texture2D before even considering SpriteBatch.Draw(). The reason I'm doing this is I'm trying to fill an arbitrary polygon, laid out with vertices defined by Vector2Ds, with an arbitrary Texture2D.
What I'm thinking of is creating the rectangle that fits the polygon, scaling the Texture2D to that rectangle, and then making the pixels that are outside of the polygon transparent via Texture2D's GetData<>() and SetData<>().
I've gotten to the point of finding the rectangle that fits the polygon, but is there a way to resize the Texture2D, or am I going about it the completely wrong way? Thanks!
You're going about it the wrong way. Setting texture data is expensive. (And there's probably some issues with filtering, too.)
What you want to do is set the texture coordinates (the "UV coordinates") of the vertices you are drawing. This will cause a specific location of your texture to appear at that vertex of your polygon. The texture that would then fall outside your polygon is simply never drawn (it is "clipped" by the polygon edges).
Texture coordinates are specified in the range 0.0 to 1.0 (on the U and V axies - horizontally and vertically) from the top left to the bottom right of your texture.
If you are drawing using vertex buffers, XNA includes some built-in vertex structures like VertexPositionTexture and VertexPositionColorTexture that allow you to specify a TextureCoordinate value.
If you are using your own vertex structure, use VertexElementUsage.TextureCoordinate when specifying a VertexElement. If you are creating your own shader, the value will be exposed in TEXCOORD0 (for usage index 0).
If you are just drawing rectangles with SpriteBatch, then specify a sourceRectangle when you call Draw.
Sounds like you should be using the overloads on the Draw method (I realise you are for some reason not wanting to do this, but it's like this for a good reason):
public void Draw (
Texture2D texture,
Vector2 position,
Nullable<Rectangle> sourceRectangle,
Color color,
float rotation,
Vector2 origin,
Vector2 scale,
SpriteEffects effects,
float layerDepth
)
The sourceRectangle, scale parameter, and origin should be enough. Don't modify the texture in memory, it's relatively expensive to do this (especially doing it every frame!)
http://msdn.microsoft.com/en-us/library/bb196420(v=xnagamestudio.31).aspx
Can you explain why you don't want to scale in Draw()?

MonoGame - Tiling Texture2D with SpriteBatch on iOS

Right now I'm tiling a Texture2D with 2 for-loops similar to an example from the MonoGame samples.
I was doing some reading, and I was seeing that using power of two textures (2, 4, 8, 16, 32, etc. on width & height) can be tiled with one SpriteBatch.Draw call.
Is this supported with MonoGame on iOS?
I gave it several tries, and no matter what it merely stretches the image instead of tiling it.
I am using SamplerState.LinearWrap on my SpriteBatch.Begin(), and tried using a 2048x128 png and tried it 1/4 size at 512x32, but with no luck. (Using large sizes, b/c our game runs at 2400xSomething zoomed out, b/c you can zoom in with the camera by 2.5 multiplication)
You can use the SourceRectangle parameter in the draw method. To define what part of the Texture you want to display. Lets say you have a 128x128 Texture. If you supply Rect(0, 0, 128, 128) you tell the draw method to use the whole texture, the same if you would pass null to the draw method. If you supply Rect(0, 0, 64, 64) you would use the upper left part of the texture. Your sprite will display this portion, no matter how big the sprite itself is. So if your sprite is drawn with the size of 128x128 the 64x64 texture part would be scaled.
Now you can use that for animations. If you store in your texture a sequence of animation like this, you just need to recalc the source rectangle everytime you want to display the next image in your sequence.
Besides that, you could pass in a bigger value, than your source texture. XNA now needs to wrap or clamp your texture. That way you can achieve a simple tiling. If you need more than that my guess is you need to use a manual approach, like your foreach loops.
Please note that Wrap is only supported if you use power of two textures.

Color single pixel in XNA

Give a Coordinate, how can I color a single pixel in XNA? i.e.
Coordinate(10,11).Color = Color.Red
If you're planning on doing a lot of pixels, for something like a particle system, it would be better to use a shader. You'll probably run into performance issues eventually just using a SpriteBatch.
There's two ways depending on what coordinates you mean:
For screen coordinates the easiest way is to have a Texture2D that holds nothing but a single white pixel, then drawing it with SpriteBatch and passing whatever color you want to the Draw method.
For 3D space coordinates you want to use a PointList.
There's a bit more complicated things you could do as well: use Texture2D.SetData to make your own single white pixel texture at run time. Or, it's also possible to use a PointList and project to screen space.

Categories