Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm working on a voxel game, and I have some problems with texturing. I have read the related questions on this stack exchange, but they seem adressing a generic problem (using triplanar texturing), and I think mine is simpler.

Polygonization output

You can see that the resulting geometry contains a limited set of polygons. Last I checked I saw only 44 of them. My idea was to uv map these polygons to a regular texture using a static map table, without having to use any triplanar texturing (currently, every polygon is mapped to the same values, so it's ugly).

My questions :

  • Is it valid ? It seems much simpler than triplanar texturing, but I can't find a single resource on the subject, so I'm wondering if it's a right approach.
  • Where can I find / How can I generate a UV map for this kind of geometrical figure ? I have tried to use blender but it seems like my blender-fu is not strong enough. Is there some simpler software to generate UV map with models like this one ?
share|improve this question
3  
I wont post this as an answer, but this link describes the process of tri-planar texturing in the exact same context you are trying to use it in http.developer.nvidia.com/GPUGems3/gpugems3_ch01.html –  Evan Apr 4 '13 at 5:22
    
This seems to me to be the same kind of problem as constructing a tile-set with transition tiles for a 2D map: for each type of edge, you need to decide what that edge looks like, then make a set of texture tiles + UVs such that no matter what the neighboring polygon is, its edge (of that type) always has the same pattern on it. It sounds like you want to accomplish this using only a single texture and only adjusting the UVs but that may not be possible (except in the trivial case where every edge has the same pattern). –  Kevin Reid Apr 4 '13 at 19:05
    
A problem I'm having with this approach is selecting the correct texture for each vertex, given multiple options. You can't simply select the texture of the closest voxel to that vertex, since "air" voxels have no texture. In the air case, you have to resolve to another voxel, and I'm racking my brain in an attempt to come up with something efficient. You can't simply map an air voxel to another voxel for all vertices, so you must either encode more specific logic, OR use a lookup table somehow. Hmm... –  Philip Apr 12 at 18:17

3 Answers 3

Another way would be to procedurally generate your textures. This approach comes with its advantages and disadvantages. Most important tradeoff is that you can't draw your textures in an editor but have to code them using noise functions.

The huge gain in your situation is that you can texture your terrain completely orientation independent. This is done by using so called solid noise. It is a three dimensional noise function.

Using that you can code a function to generate the color value of any given position in 3d space. Then you sample just the points lying on the mesh faces. In other words, you carve out from the three dimensional texture.

This is from the libnoise glossary.

The following image shows an object that has a solid noise texture. Note that the texture does not warp anywhere on the object; it is uniform throughout the object. It would be very difficult to produce a non-warping two-dimensional texture map for this object.

enter image description here

I know that it may not be your aim to code instructions for generating every texture you want to use. But it may also be a challenge and comes not only with the orientation independent advantage but also with heavily reduced storage space and unlimited zoom-in detail.

I would be very interested if you would try to implement solid noise textures for your terrain.

share|improve this answer

So this doesn't provide details to every problem you'll encounter with your approach, but, if you want to map each vertex to the closest non-air voxel in order to scrape information from it (such as which texture to sample), here's a proof for the efficient method I came up with:

For any given marching cubes vertex, we wish to select a voxel with which to infer the vertex's attributes. We choose the closest non-air voxel, which by its definition must be located along the same edge the vertex is placed on. Furthermore, because the 'surface' we generate delineates air from solid, it follows that the two voxels along an edge containing a vertex must be one solid, and one air. Therefore, if each voxel adjacent to the current cube is indexed by the combination of it's inclinations along each axis, then we may infer two of its inclinations by the particular edge on which the vertex rests, and the third inclination by sampling both possible corners and selecting only the one that is solid. Thus, to sample the desired voxel efficiently, we establish a lookup table mapping each of the twelve cube edges to two possible voxel indices each, the upper and lower four bits of each being indices into the set of eight possible voxels. After sampling both voxels, we may add the two samples together rather than branching in order to select the solid one. If 'air' is a non-zero value, we may simply subtract it from the final result, since one of the operands is guaranteed to be that value.

Here's my implementation in Java, assuming corners and edges are indexed as described in Paul Bourke's popular article (corner zero being -X -Y -Z):

Paul Bourke's popular reference on marching cubes

..and assuming that blockIds is a long whose bytes each correspond to a corner, from most to least significant, 0, 1, 4, 5, 3, 2, 7, and 6. (In terms of inclinations XYZ, the ordered values are 000, 100, 010, 110, 001, 101, 011, and 111.)

private static final byte[] BLOCK_PICK_BITS_BY_VERT_INDEX = new byte[]{
    (byte)0x67,
    (byte)0x26,
    (byte)0x23,
    (byte)0x37,
    (byte)0x45,
    (byte)0x04,
    (byte)0x01,
    (byte)0x15,
    (byte)0x57,
    (byte)0x46,
    (byte)0x02,
    (byte)0x13
};

private static final int pickBlockIdForVertex(long blockIds, int vertIndex)
{
    int bits = BLOCK_PICK_BITS_BY_VERT_INDEX[vertIndex];
    int blockIndexA = bits >> 4;
    int blockIndexB = bits & 0xf;
    int blockIdA = (int)(blockIds >> 8 * blockIndexA) & 0xff;
    int blockIdB = (int)(blockIds >> 8 * blockIndexB) & 0xff;

    //assert (blockIdA == airBlockId) != (blockIdB == airBlockId);
    //return blockIdA - nonZeroAirBlockId + blockIdB; 
    return blockIdA + blockIdB;
}

In C/C++, it could make sense to change long blockIds to an array of bytes/shorts/pointers, and remap each four-bit value in the table according to bits = 7 - bits. I haven't profiled it, though, so packing everything into a long may still be faster. Finally, in case of a non-zero air blockId, it's reordered so that in case of a large domain of blockIds, no overflow occurs. Wouldn't happen in the code above, since I'm using ints to store blockIds which are bytes, but it's something to consider.

(To be 100% clear, I contribute this method to the public domain and waive liability according to the full license described here: http://unlicense.org/)

share|improve this answer

UV mapping does look like the correct way to go with this. I believe this answers your first question (but I may be wrong). About why Blender won't UV map this for you is because it's trying to unwrap it as one giant lump-thing. You need to add seams to the model so that Blender can split it appropriately - look at Blender's Official Guide to UV Mapping to see how to do this.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.