• Advertisement
Sign in to follow this  

Sprite Masking

This topic is 4268 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm a beginner to DirectX and Windows, but not a beginner to programming. I have a long history in Macromedia (now Adobe) Flash, and am currently attending the DigiPen Institute of Technology (going into my sophomore year next year). I know my way around C/C++. That said, I was hoping to do a Mode 7 racing game (ala Super Mario Kart or F-Zero) for my project next year. I've already done something similar in Flash, so I know how it works. However, the one dilema I've encountered has to do with masking... In Flash, I'd create multiple rectangles and use those to mask respective copies of the level pic, then do the scaling and rotation, which of course creates the illusion of perspective. Flash has a handy little function called setMask() that makes it quite simple. The problem is that I have no idea how to do masking like this with DirectX. I've looked all over MSDN and Google to no avail. I'm crossing my fingers I overlooked something simple. Any ideas? Thanks, Marshall

Share this post


Link to post
Share on other sites
Advertisement
You could probably do it with something like alpha blending. I presume that the mask you are talking about has some opaque color values and the a alpha mask. This can be done in Direct3D, although I don't recommend it as Direct3D provides you with a foundation to easily get perspective.

Open the documentation and go to
DirectX Graphics --> Direct3D9 --> Programming Guide and start reading from there.

I hope this helps.
Take care.

Share this post


Link to post
Share on other sites
The project for next year must be 2D, I believe. I'm not even sure if I can do Mode 7 yet, I'm still waiting on a response from the instructor.

The mask I'm talking about is just a simple rectangle. The only opacity is on or off. Here's a picture of what I'm talking about...

http://i3.tinypic.com/xdfrdj.jpg

Each red rectangle is a mask that is only displaying a specific part of the image. Is there no easy way to do this with DirectX?

Share this post


Link to post
Share on other sites
Alpha blending or alpha testing. With alpha testing when you load in a texture in d3d (using the D3DXLoadTextureFromFileEx function), you can spcify a color key. The texture loading function will load your texture and manipulate the color values of your texture. If you set a green (0xff00ff00) key for example, it will check each pixel in your texture and make all the pixel that match your key transparent black (i.e. set them to 0x00000000).

Then when you are rendering the texture, you tell d3d to ignore pixels that have an alpha value below some threshold, and those pixels will not be shown. Check out SetRenderState and D3DRS_ALPHATESTENABLE

Share this post


Link to post
Share on other sites
I'm not trying to mask specific colors on the map though. Any pixel on the map could potentially be shown if you drive over it.

Here's another example:
http://i2.tinypic.com/xdgjuf.jpg

This rectangle is a lot bigger than the actual thing, but it's the same idea. The map is rotated around depending on the turning you make while driving. The map's x/y position shifts as you drive along. What you actually see is only on that rectangle, which makes up a fraction of what's actually drawn. There's multiple copies of the same thing. When drawing the screen, as the y pos on the screen goes down, the mask gets larger (vertically), and the map scales larger. Line all these up and it creates the illusion of depth. (See the pic in my last post for the effect.)

All I need it to do is show what's in the red rectangle, and hide everything outside of it.

Share this post


Link to post
Share on other sites
Guys are you sure he's not just asking about texture coordinates?? Sounds to me like that's the best way to pick out a rectangle from a larger image to be (drawn/distorted/skewed/etc) to make the fake 3D effect. You'll be using Direct3D polygons but in a 2D way, which is very common. Just my $.02

Share this post


Link to post
Share on other sites
You can display a specific part of an image by loading the image as a texture, then give each vertex texture coordinates.

But you probably want to approach this in a fundamentally different way if you are using Direct3D. Draw the ground as a big 3D quad using the ground racetrack image as the texture.

Share this post


Link to post
Share on other sites
From your second example (that you posted while I was writing the first reply!) I definitely think you're looking for info on texture coordinates. The hardest part is going to be calculating the (tu,tv) pairs for each of the four corners of that red box (which I'm sure you've already thought about). Once you do that you can render that part of the texture into your perspective polys, and Direct3D will handle any stretching/skewing/etc as necessary.

Just for starters, the texture coordinates (tu/tv) are inserted into every vertex that you render. Typically one quad requires 6 vertices (2 triangles), but with index buffers you can cut it to four vertices and reuse the 2 overlapping ones.

Just out of curiousity, why must the perspective view be subdivided into so many little rectangles (as you show in the first picture)? Couldn't you do it all in one go?

Share this post


Link to post
Share on other sites
Ok, I'll look into that then.

It's not possible to do it in one go, because behind each mask the image is a different size. The lower on the screen the mask is, the larger the image it's masking is. If you did it all on one go, you'd be looking at a flat map.

Here's a link to the Flash version I have:
http://flash.isnan.net/index.php?height=300&width=600&bg=FFFFFF&url=kart.swf&name=Mario%20Kart%20Engine

Look close and you can see where the masks are.

Flash is abysmal at handling 3D stuff (and is just flatout slow in general), so this masking technique actually works quite well. If it turns out I can do 3D, I'll just do a 3D quad, as that sounds easier.

Please forgive my general ignorance on the subject. The most advanced stuff I've done with DirectX so far has been Breakout.

Share this post


Link to post
Share on other sites
Sorry for the double post, but I'm a bit lost on this.

In Flash, the mask was incredibly easy to make. All I had to do was use the drawing API and tell it the physical coordinates on the screen to make a rectangle. Then just use that rectangle for a mask. No fancy math needed.

Obviously I can't do this with DirectX, and I know MasterWorks mentioned finding the (tu,tv) pairs for the 4 corners. Where do I tell DirectX to use these pairs? I know in the ID3DXSprite::Draw() function, you can provide a RECT that it will grab. Problem is, I'm doing rotation, and the function doesn't seem to account for that. Is there some other way I can grab a specific area from the texture using 4 coordinates?

Share this post


Link to post
Share on other sites
You can mask using the stencil buffer. (It does seem a little strange to go through all this trouble to "fake" 3D on hardware that excels in doing realtime 3D, but I guess it's a requirement for the class.)

Share this post


Link to post
Share on other sites
The 4 (tu,tv) pairs go into the vertices that you use to draw your quads. (Making your quad out of 2 triangles, you will need 6 vertices but 2 of them are repeated. There is lots of information on this available.) So your vertex structure might have an X, Y, Z, TU, and TV for each vertex. Then when you render those 6 vertices as a triangle strip (or triangle list) DirectX will reference your TU and TV to decide how to texture the quad.

The sprite interface is designed to automate most of this process (drawing 2D textured quads) but it doesn't do anything special that you can't do "by hand". Just look up how to render a textured quad and then feed the vertices the TU and TV that you calculated. (Your screen position for the quad will be determined by what you put in .X, .Y, and .Z, although .Z might not be relevent if you're using screen coordinates.) Then DrawPrimitive will stretch your pixels to make them fit inside your quad, even if the quad is distorted in some way.

Don't get caught up too much in the '2d vs 3d' stuff, because all 3d hardware does is draw textured quads very fast. Usually those quads are arranged to give a 3d appearance but you can use them however you please and still get excellent performance. Also, I dont think the stencil buffer is useful here (correct me if I'm wrong) because he's trying to 'mask' the image SOURCE and not the image DESTINATION. It might be a terminology issue? I think it's more of an 'extract' operation or something than a masking operation.

Share this post


Link to post
Share on other sites
Destination would be easier, but theoretically it could be done both ways. Look, here's a physical working example of what I'm trying to do:

http://flash.isnan.net/index.php?height=400&width=550&bg=FFFFFF&url=masking.swf&name=Masking%20Example

Just wait for it to load, it's like 500 kb. Move with the arrow keys. Turn the mask on and off with Enter.

That's ALL I'm trying to do. I looked up stencil buffers and it looks like overkill, if it's even applicable in the first place. There's no way to do this with the sprite interface? I have to access the individual verticies?

[Edited by - marshdabeachy on May 7, 2006 2:14:38 PM]

Share this post


Link to post
Share on other sites
The sprite interface just automates the task of making a simple sprite, but since your task isn't particularly simple you might have to do it by hand. You seriously don't have to write any new code. Even the most basic samples will show you how to draw 2 textured triangles with 6 vertices to make a quad. Copy and paste, and insert your special code to calculate the TU and TVs! You want to understand what's going on and not just use a 'black box' sprite interface and pray it works for you anyways.

This is absolutely the way to do what your samples wants. I don't know how much more help people can give you because you're trying to do the same thing that EVERY beginner does, draw some triangles!! You may be caught up in the differences between 2D and 3D APIs, there's no (easy) way to do certain things in 3D that are trivially easy in 2D. You're not working with pixels anymore, you're working with vertices/vertex buffers, textures, and DrawPrimitive. There's just no way around that fact... when I got started I couldn't believe that there was no easy way to just 'draw' a background to the screen from a basic bitmap, but it's true. Any workarounds that involve pixel processing, etc. are waaay too slow for normal use; you've just got to use the pipeline and even though it is actually more complicated for certain simple 2D tasks, the benefits of scaling, rotation, translucency, etc. more than make up for it.

To make a DX program similar to that Flash sample you posted, you would just have 4/6 vertices that sit in the middle of the screen and never move. Every time the point of view changes/rotates, you update the texture coordinates. That's all there is to it.

Share this post


Link to post
Share on other sites
Just a few more thoughts, sorry if it's too much to swallow all at once:

I still think terminology here is the issue. You're asking people how to NOT DRAW a part of your texture onto a quad. The question you could be asking instead is how TO DRAW a specific part of a texture onto a quad. It's significantly different than the 2D approach.

I understand if you're trying to do this the 'hard way' for a programming project or whatever, but the 'right way' is to have ONE quad be your ground. Set the vertices up in the XZ plane (or whatever) and then just move/rotate the camera matrix (or the transformation matrix if you prefer) and render. It will look better and it's trivially easy -- you don't even need texture coordinates. Just draw the entire ground every frame on a quad from like (-100,0,-100) to (100,0,100) or something. Much faster, easier, and allows the GPU to do the work that you're doing by hand.

Your comment
Quote:
'It's not possible to do it in one go, because behind each mask the image is a different size. The lower on the screen the mask is, the larger the image it's masking is. If you did it all on one go, you'd be looking at a flat map.'
doesn't make sense. You're just trying to draw a perspective-correct ground. The only reason it would look flat would be if the camera was up high and looking straight down (perpendicular). If the camera is low and looking straight ahead (parallel to the ground) the ground will be drawn with the texture converging to a vanishing point/horizon the way Mario Kart does. Plus you get the massive benefit of essentially getting infinite little 'masking rectangles' because the GPU is designed to draw textures in perspective, and it can do it far more efficiently than you can, and most importantly, in parallel with your engine.

Basically I am saying that if you get it to work your way you will just be approximating the results obtained from the '3D' way. Good luck however you approach it, be sure to post some screenshots. Note that you can still have 2D sprites for all your objects, characters, etc. even if you draw the ground in '3D'.

Share this post


Link to post
Share on other sites
Ok, I finally got it working. Took some funky trig, but I got it drawing perspective without using the z-axis. I'll post a screen after I get this next thing fixed.

This is just a follow-up question. Is there any way to prevent textures from tiling? If you drive off the map, it would ideally just fill the empty area with a solid color. Is this possible?

[edit] Nevermind, got it fixed here: http://www.gamedev.net/community/forums/topic.asp?topic_id=393205

Here is a shot of it. Remember, no z-axis used at all.

http://i3.tinypic.com/zv90mh.jpg

[Edited by - marshdabeachy on May 16, 2006 2:08:58 AM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement