DSent

My question is rather simple.
I have a texture and a landscape map to apply it to.
It is possible to make a rectangular sprite in XNA, but is it possible to cut a part from it

Here's an example for better understanding of what I'm aiming for:
http://img335.imageshack.us/img335/9972/examplent7.jpg

The only way I can think of is to make a different texture for every sprite, changing its shape every time.
But that really it not the easiest and smartest way...



Re: XNA Game Studio Express Question regarding making landscape in 2D

X-Tatic

Make it transparent...




Re: XNA Game Studio Express Question regarding making landscape in 2D

lethil

It sounds like you want to use alpha transparency on your sprite.

I might be missing some context in your query, but use of alpha transparency will -- in effect -- cut out that part of the texture that you don't want.

Most image editing software will allow you to create transparent images.

The only other part to be aware of is the call to the SpriteBatch when drawing, which would be:

SpriteBatch.Begin(SpriteBlendMode.AlphaBlend);

I hope this helps!





Re: XNA Game Studio Express Question regarding making landscape in 2D

BlueG

I'm a little confused as to why you want to cut out a part of your texture given your illustration.

Assumming that you know which parts to cut out beforehand, then adding an alpha channel to your texture would be the way to go (as others have suggested). If you don't have a paint program that generates the alpha channel for you (or you'd rather create the alpha channel as a seperate file), then you can use the DirectX texture tool (from the DirectX SDK) to accomplish this.

However, it seems to me that you want to do this dynamically at run time for some reason. In that case, I can see two options:

  1. You use GetData on the Texture2D object containing your texture to get the texture data, modify the alpha transparency of each pixel in the data so that the parts you don't want to draw are fully transparent and the parts you do want to draw are fully opaque, and then call SetData on the Texture2D object to write the new texture back again. To improved performance a bit, you'd want to keep a copoy of the data you retrieved using GetData since (based on your description) you won't be changing the color data, only the alpha transparency. But, the rest you would have to do every time the area you are trying to clip changes.
  2. You create a seperate Texture2D object that you use to mask your original texture. In earlier versions of DirectX, this could be accomplished using texture stages. In this version, I believe you'd have to write a texture or pixel shader. You would then generate that texture's data with each update to the clipping region.

Both these techniques are little rough on the system bus, but might be acceptable for your application. It can be reduced, somewhat, by only updating the parts of the texture (or textures) you need to update by specifying a rectangle during GetData and SetData. There are ways you could move this process onto the GPU instead of the CPU as well, but... like I said, I'm not exactly sure what you're trying to accomplish.

However, it seems to me, based again on your illustration, that you shouldn't need to clip the texture at all. If you already have your landscape loaded as a mesh then simply using the right texture coordinates inside your mesh vertex data would cause only the parts you want to render to be displayed. Generating those texture coordinates is simple multiplication. I guess my question would be, how are you generating your landscape

In any case, multiple sprites can be contained inside a single texture. When you go to draw the sprite, you simply specify the area of the texture to use for drawing the sprite. You can make your life easier by creating a structure or class that holds this information for each sprite (what texture to use for the sprite and what area of the texture to use for the sprite). As I write this, it occurs to me that this is probably what you are looking for. If that's the case, look at the documentation for the Draw method of the SpriteBatch class. The source rectangle parameter used by some overloads of this method is what you'd need to specify. There are no examples in the documentation of of how to do this, but it should be obvious.






Re: XNA Game Studio Express Question regarding making landscape in 2D

DSent

You're right, reason why I couldn't just create a texture with transparency is because in my particular case there won't be any predefined shape, they will be changing dynamically.

The first 2 options you suggested look interesting, but as you already mentioned, they will load the processor quite heavily.

>>When you go to draw the sprite, you simply specify the area of the texture to use for drawing the sprite
That's exactly what I need!

I've found an overload for the Draw method that lookes like this:

public void Draw (
Texture2D texture,
Rectangle destinationRectangle,
Nullable<Rectangle> sourceRectangle,
Color color,
float rotation,
Vector2 origin,
SpriteEffects effects,
float layerDepth
)

sourceRectangle - A rectangle specifying, in texels, which section of the rectangle to draw. Use null to draw the entire texture.
I think that's the one I need.
Now I have to figure out how to use it...any ideas For example, what if I want to draw the sprite3 from my example, what should I put in the sourceRectangle variable

Thank you very much for the help!





Re: XNA Game Studio Express Question regarding making landscape in 2D

errolian

As it requires a Rectangle, you still wouldn't be able to produce a non-rectangular shape as you would like.





Re: XNA Game Studio Express Question regarding making landscape in 2D

DSent

You're right...
But there's gotta be some way to select only a part of a texture, by using vertices.

BlueG wrote:
If you already have your landscape loaded as a mesh then simply using the right texture coordinates inside your mesh vertex data would cause only the parts you want to render to be displayed.

Could you please explain this in more detail How do I set the mesh vertex date and apply it to the texture
Thanks in advance!





Re: XNA Game Studio Express Question regarding making landscape in 2D

BlueG

I didn't realize from your original post that you were trying for nonrectangular shapes. Landscapes typically involve only rectangles and triangles. Will you be able to use triangles to represent the shape you want

If so, then using the DrawUserPrimitives method of the GraphicsDevice method would let you specify the vertices (along with their texture coordinates) at run time. Depending on the details of your application, you may be able to use a vertex shader instead (which would be faster since it would execute on the graphics adapter, avoiding the system bus).

If not, then you'll need to use one of the texture masking techniques (either updating the texture at runtime or creating another texture to mask it).

Maybe I'll put together an example of using the DrawUserPrimitives method with texture coordinates and post it a bit later. Basically, though, it should look something like this:

int i;
VertexPositionTexture[] vertices = new VertexPositionTexture[GetNumberOfVertices()];
for( i = 0; i < vertices.Length; i++ ) verticesIdea = GetVertex( i );
device.DrawUserPrimitives<VertexPositionTexture>( PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3 );

Mind you, I haven't tried this code yet. Nor have I had to use DrawUserPrimitives under XNA (I have used it under Managed DirectX). I could be totally off about how it works in XNA. The GetNumberOfVertices and GetVertex functions are simply placeholders for fetching the actual vertices to use. In other words, you'd have to define them as appropriate. The vertex format choosen here, VertexPositionTexture, would let you define texture coordinates as well as the position in 3D space of each vertex. The device is the GraphicsDevice object, not the manager. It can be retrieved using the GraphicsDevice property of the GraphicsDeviceManager.






Re: XNA Game Studio Express Question regarding making landscape in 2D

BlueG

Well, I was close. What I had was correct, but I forgot a few steps needed to make that code work. Namely, I had to use an effect to set the Vertex and Pixel shaders. I'm not going to post my entire project here, but the following are the key sections.

First, anywhere in the class definition:

BasicEffect effect;
VertexPositionTexture
[] vertices;
VertexDeclaration declaration;

Next, in the LoadGraphicsContent method:

effect = new BasicEffect( graphics.GraphicsDevice, null );
effect.LightingEnabled =
false
;
effect.World =
Matrix
.Identity;
effect.View =
Matrix.CreateLookAt( new Vector3( 0.0f, 0.0f, -10.0f ), new Vector3( 0.0f, 0.0f, 0.0f ), new Vector3
( 0.0f, 1.0f, 0.0f ) );
effect.Projection =
Matrix.CreatePerspectiveFieldOfView( MathHelper
.ToRadians( 45.0f ), 1.0f, 1.0f, 100.0f );
effect.Texture = content.Load<
Texture2D>( "shinobu"
);
effect.TextureEnabled =
true
;

vertices =
new VertexPositionTexture
[4];
declaration =
new VertexDeclaration( graphics.GraphicsDevice, VertexPositionTexture.VertexElements );

Next, in the Update method:

float d = (float)( gameTime.TotalGameTime.TotalSeconds / 8.0 );
d = d - (
float)Math
.Floor( d );
if
( d > 0.5f ) d = 1.0f - d;

vertices[0].Position =
new Vector3( -2.0f, 2.0f, 0.0f ); // top left
vertices[1].Position = new Vector3( -2.0f, -2.0f, 0.0f );
// lower left
vertices[2].Position = new Vector3( 2.0f, 2.0f, 0.0f );
// top right
vertices[3].Position = new Vector3( 2.0f, -2.0f, 0.0f );
// lower right

vertices[0].TextureCoordinate = new Vector2( 0.0f + d, 0.0f ); // top left
vertices[1].TextureCoordinate = new Vector2( 0.0f + d, 1.0f );
// lower left
vertices[2].TextureCoordinate = new Vector2( 1.0f + d, 0.0f );
// top right
vertices[3].TextureCoordinate = new Vector2( 1.0f + d, 1.0f ); // lower right

Finally, in the Draw method:

graphics.GraphicsDevice.VertexDeclaration = declaration;
effect.Begin();
foreach( EffectPass pass in effect.CurrentTechnique.Passes )
{
pass.Begin();
graphics.GraphicsDevice.DrawUserPrimitives<
VertexPositionTexture>( PrimitiveType
.TriangleStrip, vertices, 0, vertices.Length - 2 );
pass.End();
}
effect.End();

A pretty useless example (other than for my Shinobu worship), but it does demonstrate setting vertex texture coordinates every frame. Most of this should be stuff you already know how to do from following the tutorials, but was included for context. To see a more complete example, check out the "How to: Use BasicEffect" documentation in the XNA help file. That example uses a vertex buffer to store the vertex data. If you're going to change the vertex data every frame, I don't know which would be more efficient.

To apply this to your problem, you could create the vertex buffer each frame using whatever format you need to. Sending the vertex data across the bus each frame is less expensive than a texture. Of course, depending on the details, you may be able to write a custom vertex shader instead so as to do all the work on the graphics card. To do so would, among other things, require that the number of vertices be the same each frame. In fact, I could easily have used a custom vertex shader for my example, but I was more interested in just showing how to set texture coordinates on the vertices.






Re: XNA Game Studio Express Question regarding making landscape in 2D

DSent

>> Landscapes typically involve only rectangles and triangles. Will you be able to use triangles to represent the shape you want
Yes, basically, each part of my landscape would consist of rectangle in the bottom and a triangle on top.
The bottom rectangle could also be represented by 2 equal triangles.





Re: XNA Game Studio Express Question regarding making landscape in 2D

DSent

>>Well, I was close. What I had was correct, but I forgot a few steps needed to make that code work. Namely, I had to use an effect to set the Vertex and Pixel shaders. I'm not going to post my entire project here, but the following are the key sections.

Thank you very much for the detailed explanation, I'm going to create a class from your example, and will show the result.

>>If you're going to change the vertex data every frame, I don't know which would be more efficient.
Actually, there's no need to change it every frame. It will be loaded in the beginning of the game from some map file, that would contain all the vertices needed.

>>you may be able to write a custom vertex shader instead so as to do all the work on the graphics card
Could you please write some simple example on how to create a custom vertex shaders I think that's what I need.

>>To do so would, among other things, require that the number of vertices be the same each frame
That would be 4. Basically, each part of the landscape will consist of 4 corners, as you can see from my example picture.

>>In fact, I could easily have used a custom vertex shader for my example
That would be great, because I think that's what I need...if you say it would be faster this way.

Thanks again!





Re: XNA Game Studio Express Question regarding making landscape in 2D

DSent

Here's an example of a single landscape part:

http://img151.imageshack.us/img151/8537/partaq9.gif





Re: XNA Game Studio Express Question regarding making landscape in 2D

BlueG

Alright... now I finally understand what exactly you are doing and why. You're creating a landscape for what seems to be a platform style game and you want to use vertices so you have slopes instead of a block landscape. As a consequence, when you first load the level, you are able to generate the landscape once and then leave it alone, but you haven't been able to figure out how to apply your textures to a sloping landscape like that. I'm guessing that it's safe just to tile the texture, even between parts of the landscape, but the resulting tiled image needs to be clipped. That is, it would be as if you took your texture, tiled it across the entire screen surface, and then cut out parts of it so your original background showed through again.

Fortunately, this is easy to do. And, incidentally, you can do it with two triangles per segment of your landscape. The shape you showed with a triangle and a rectangle could easily be represented as just two triangles (but not right triangles). In fact, it's surprisingly close to what I was doing in my example. Though, you'd want to use TransformedTextured vertices instead of PositionTextured ones.

I feel another example coming on...






Re: XNA Game Studio Express Question regarding making landscape in 2D

DSent

Thanks for helping me out! A simple example would be very useful as I couldn't find this in the documentation...





Re: XNA Game Studio Express Question regarding making landscape in 2D

HippyInASuit

What he wants to do is basically just masking, correct

Take a tiled rectangle of the texture that will cover the entire background (either the sky or the ground ), plus a little extra tiling since that is just how it comes out. Then set total transparency on the tiled texture image on each pixel that is not part of the background. Then display your textured background.

I would enjoy an example too!