5
\$\begingroup\$

So, I want to use textures for weapons in my FPS game instead of actual models. However, if I just draw the texture onto a square in the game, it has the rotation and stuff, but it looks "2D". How can I make it look like it has width?

The best example I can think of is probably Minecraft. If you hold a tool in Minecraft (such as a pickaxe), the texture is drawn and it has an "edge" that shares a color with the color of the actual pixel next to it.

That was probably really confusing, so here's a picture of what I mean: Original: Minecraft tool with edge

Edge highlighted: Highlighted edge

How can I do this with XNA?

My code basically makes a square right now (four vertexpositiontexture vertices), and I use BasicEffect to attach an image to it.

\$\endgroup\$
6
  • \$\begingroup\$ Why not just extrude it using the image as an alpha/colour map? \$\endgroup\$
    – ashes999
    Commented May 10, 2012 at 3:00
  • \$\begingroup\$ How does that help me create the "edge" effect? Doesn't an alpha map just tell the renderer about transparent places? \$\endgroup\$
    – untitled
    Commented May 10, 2012 at 3:21
  • 1
    \$\begingroup\$ You could simply create a cube for every pixel in your texture that is not 100% transparent. You could also identify the outer boundaries in your texture, and use those positions to create the rim; then just put two flat squares with the texture on either side. \$\endgroup\$
    – user13213
    Commented May 10, 2012 at 3:37
  • \$\begingroup\$ Wouldn't that be rather inefficient, though? Is there no way I can do some magical (for lack of a better word) technique that will allow an edge to appear? \$\endgroup\$
    – untitled
    Commented May 10, 2012 at 3:51
  • 1
    \$\begingroup\$ Is there a reason you can't just create a model that matches the shape of the texture, and UV map it accordingly? Otherwise you need to generate the vertex data based off the texture and extrude it like ashes999 suggested. \$\endgroup\$ Commented May 10, 2012 at 5:10

4 Answers 4

3
\$\begingroup\$

This is how I do it in my Minecraft clone: http://pastebin.com/10JH8HHF

I apologize for the lack of comments in the source, however I will try to explain here:

I will skip explanation of the Direct3D specific code - all it is doing is getting access to the texture data in memory.

  1. The function is called with one of the arguments a pointer to an array of vertices. The array must be the maximum possible size to ensure no buffer overruns.

  2. I loop through each texel in the texture (the 2 nested loops) and check the alpha value of each texel. If the alpha value is zero, I simply continue; to the next texel.

  3. When a non-zero-alpha texel is found, I create the front and back faces for the "3D texel" or cube representing the texel. I set the color of the cube vertices to the color value from the texture.

  4. Then I check the alpha values of the texels on each of the four sides of the texel, and if there is a zero-alpha texel, it means the texel is an edge, and therefore I create the corresponding face (i.e. left face).

  5. Mesh is created, I return the number of vertices used in the 3d mesh so the caller can then create a vertex buffer of the correct size.

And we are finished! The result: (my MC clone)

3d mesh from 3d texture

\$\endgroup\$
3
  • 2
    \$\begingroup\$ You should definitely expand your answer more with extra explanations. As it currently stands, it's a very poor quality answer. \$\endgroup\$
    – user15805
    Commented Aug 24, 2013 at 11:08
  • 1
    \$\begingroup\$ +1 for the explanation and providing source code. However this implementation does not provide surface normals and creates non-optimized meshes, where the number of faces is proportional to the size of the bitmap instead of proportional to the complexity of the boundary. Normals can be post-generated, but as you are baking the vertex colors instead of runtime-lookup from a texture, the faces cannot be combined. \$\endgroup\$
    – msell
    Commented Aug 25, 2013 at 5:12
  • \$\begingroup\$ Sorry, I forgot to explain that bit... The code actually does lookup the vertex colors from the texture. However I haven't bothered to combine faces yet since it's a relatively small mesh. I probably will do it eventually though. \$\endgroup\$ Commented Aug 25, 2013 at 9:20
4
\$\begingroup\$

Two approaches come to my mind:

  1. Render bounding box of the object. The box would be an extrusion of the quad that you are currently rendering. Then implement a shader that does raymarching inside the box to look for texels. This is like volume rendering a 3D texture, but the depth of the texture is 1. This might not be efficient enough though. The positive side about this solution is that after implementing the shader you can easily use any texture.
  2. As a preprocessing step calculate all edges of the texture (including interior edges). Create a mesh based on the edges. There are probably many ways to find the edges, but the following algorithm should be quite simple to implement.
    1. Start by creating two vertices in the corners between and around all texels. For w * h texture you would have 2*(w+1)*(h+1) vertices.
    2. Create faces for all horizontal edges around each texel if the left side is empty and the right side is not, or vice versa. If left and right are both empty or filled, no edge is created. The normal for the face is either (-1,0,0) or (1,0,0) depending which side was empty. Do the same thing in vertical direction.
    3. To reduce the number of faces go through the faces and combine adjacent edges together where vertices are shared and the normals are pointing to same direction. If you have the faces stored in a 2D-array the adjacent faces should be fast to locate. Alternatively you can just compare all faces against each other.
    4. Remove vertices that are not referenced by any of the remaining faces.

I would choose the second approach if the textures are static. Both of the approaches can produce the same visual style you have in the screenshots. If you want less pixelated look, smooth edges, support for semi-transparency or something like that, you might need different algorithms or improve those listed above.

\$\endgroup\$
0
\$\begingroup\$

Well, minecraft uses no models it draws each pixel in the image as a cube. It uses the alpha channel to get rid of the pixels, which I don't know if XNA supports it. So pretty much I recommend going through all the pixels and render ones that aren't the color that means it's not a part of the texture.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ There's quite a lot of Minecraft-likes being made with XNA, and they all tend to draw the cubes and voxels as geometry. Since there are a lot of them on the screen at once, instanced geometry is usually the approach that people take. You can draw a ton of different-looking cubes with a single draw call if you feed a second vertex buffer with data for colors, and separate texture lookups. \$\endgroup\$
    – ChrisC
    Commented Feb 4, 2013 at 20:05
-1
\$\begingroup\$

Well this involves 3D projection drawing which is generally handled by the graphics card. It's possible to do obviously in software, but it will be a lot slower and XNA isnt really designed for that. However, what I believe minecraft does is all of the models are actually converted polygons (or they begin like that) and are drawn with textures applied. That said, if you want to draw a 3D image, just map it to a quad, which sounds like what you're doing, however maybe you could post some of your images so we can see what you are having trouble with.

\$\endgroup\$
2
  • \$\begingroup\$ Well, as I said, just drawing a "flat" 2D image to a quad looks bad; it has no edge and doesn't look 3D. \$\endgroup\$
    – untitled
    Commented May 10, 2012 at 3:47
  • \$\begingroup\$ yes, if you want it to look 3D, then you'd probably have to apply some kind of distortion mapping like normal mapping or parallax mapping, if thats what i think you want. \$\endgroup\$
    – CobaltHex
    Commented May 10, 2012 at 6:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .