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.

In the game I'm developing, rooms can be of various sizes, which means I need to vary the size of the floor texture appropriately.

The way I've solved this problem is to generate a Texture2D programatically, and set each pixel to be transparent (or not) as appropriate appropriately.

I get something like this:

enter image description here

Where, if you look at the top left, you'll clearly see the pixel artifacts from the floor texture against the dark blue background.

When I run into this with static textures, the fix is simple. Set the Texture's wrapmode to clamp instead of repeat. But when I try to do that programatically... (and change nothing else!) I get this:

enter image description here

I'm not quite sure what's happening, or why setting the wrapMode changes the results so markedly. Anyway I can avoid the pixel artifacts? I suppose it's possible to add an extra border around the generated texture (so that all edges can be transparent), but that doesn't seem a particularly clean solution.

Code is here:

void DebugFloorTextureMerge()
    {

        //sizeVector makes up the rectangle circumscribing the room's parallelagram
        Vector2 sizeVector = new Vector2(roomBounds.topRight.x - roomBounds.bottomLeft.x, roomBounds.topLeft.y - roomBounds.bottomLeft.y);

        //get the texture of the filled sprite 
        Texture2D patternTexture = (Texture2D) floorTexture.image;

        //make a new texture of the size of the room.
        Texture2D fillTexture = new Texture2D( (int) sizeVector.x, (int) sizeVector.y, TextureFormat.ARGB32, false);

            //COMMENTING THIS LINE OUT MAKES THE TEXTURE WORK WITH ARTIFACTS
        fillTexture.wrapMode = TextureWrapMode.Clamp;
            //LEAVING IT IN MAKES THE FOLLOWING CODE WORTHLESS


        int patternX = 0, patternY = 0;

        Vector2 pointVector;
        Color transparent = new Color(0,0,0,0);

        for(int x = 0; x < sizeVector.x; x++)
        {
            for(int y = 0; y < sizeVector.y; y++)
            {
                pointVector = new Vector2(x,y);
                if(roomBounds.Contains(pointVector))
                {
                    //get the next pixel
                    fillTexture.SetPixel(x,y, patternTexture.GetPixel(patternX, patternY));
                }
                else
                {
                //pixel was not in the room, so set it to transparent.
                    fillTexture.SetPixel(x,y, transparent);
                    //resultx = x; resulty = y;

                }

                //increment the pattern counter and reset if necessary.

                //if you only increment this when Contains is true, you'll warp the texture
                patternY++;
                if(patternY >= floorTexture.fillSize.y) patternY = 0;
            }

            //increment the pattern counter and reset if necessary.
            //also reset y, so the pattern will line up properly.
            patternY = 0;
            patternX++;
            if(patternX >= floorTexture.fillSize.x) patternX = 0;
        }

        //set the PixelChanges.
        fillTexture.Apply();    
    }
share|improve this question
    
What's the mesh that you're texturing? It seems like it's a large rectangle.. are you doing this to get a certain look, or why aren't you using a mesh that follows the floor shape (eg. a parallelogram)? –  bummzack Aug 13 '12 at 7:02
    
@bummzack I'm using Orthello2D which is limited to 2D rectangles. I'm not entirely opposed to making an exception for this texture, but I'm unfamiliar with how to use meshs in Unity. –  Raven Dreamer Aug 13 '12 at 11:32
    
Hm building meshes dynamically is easy and straight-forward. But then you'll probably want to build all your walls/floors like this :) The issue you're seeing with your initial approach could just be a scaling/filtering problem though. Have you tried setting "Filter Mode" to "Point" (floorTexture.filterMode = FilterMode.Point)? –  bummzack Aug 13 '12 at 12:22
    
@bummzack It's not an issue of Filter Mode (though I double checked to be sure). When wrapmode is set to repeat (the default), the edges of the texture can get blurred as the pixels from the top and bottom get blurred together. This wouldn't be a problem, except that transparent pixels still have color, so you wind up with a group of transparent pixels being blurred with a non-transparent group, giving you the ugly artifacts. –  Raven Dreamer Aug 13 '12 at 22:46
    
It really looks like you're using the wrong tools for the job - 2D graphics should be pixel aligned (which prevents such artifacts), but that's obviously not happening, and if you want to use textures you'd normally just map them to 3D objects, which would also work here without the problems you're seeing. –  Kylotan Aug 14 '12 at 0:01
show 6 more comments

2 Answers

up vote 5 down vote accepted

Instead of altering the texture and erasing pixels that should not be shown, I suggest you build your geometry in a way that it fits your floor.

Our geometry should look like this (red paint-over): triangles paint-over

To do that, we could dynamically create the required mesh in Unity (using the Mesh class). So let's assume that 0,0 of our coordinate-system lies at point 3 and our coordinates from 0 to 3 are (2,4), (6,4), (4,0), (0,0) then we would write something like this in Unity:

// vertices on XY plane, ignore Z
Vector3[] vertices = new Vector3[4]{ 
    new Vector3(2.0f, 4.0f, 0.0f), 
    new Vector3(6.0f, 4.0f, 0.0f),
    new Vector3(4.0f, 0.0f, 0.0f),
    new Vector3(0.0f, 0.0f, 0.0f)
};

// set the indices that form triangles (ccw)
int[] triangles = new int[6]{
    0, 2, 1, // top right triangle
    0, 3, 2 // bottom left triangle
};

Now we have the vertices. Next step would be to define the UV coordinates. A UV coordinate specifies the texture-position a vertex maps to. UV coordinates are normalized from 0..1. To have our texture fill the generated mesh in it's entirety, our UV coordinates would look like this:

0 => (0, 0) # Vertex 0 maps to top left of texture
1 => (1, 0) # Vertex 1 maps to top right
2 => (1, 1) # Vertex 2 maps to bottom right
3 => (0, 1) # Vertex 3 maps to bottom left

If you want to tile your texture, you can do that by specifying UV coordinates bigger than 1. So if the texture should tile 3 times across width and height, the coordinates would look like this (this time in C#):

Vector2[] uvs = new Vector2[4]{
    new Vector2(0.0f, 0.0f),
    new Vector2(3.0f, 0.0f),
    new Vector2(3.0f, 3.0f),
    new Vector2(0.0f, 3.0f)
};

Putting it all together to get an actual mesh:

Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.uv = uvs;
mesh.triangles = triangles;

// get the mesh filter component and attach the mesh to it
MeshFilter filter = GetComponent<MeshFilter>();
filter.mesh = mesh;

Of course you'll also need a MeshRenderer Component, otherwise your mesh won't render.

Here's a slightly more advanced script that allows you to specify size, origin and skew values in Unity and the Mesh gets generated on the fly (script is just a quick and dirty example to illustrate the concept). Here's how it looks in Unity with a MeshRenderer that has a checker texture applied (the texture repeats with the Size parameter).

script in unity screenshot

share|improve this answer
add comment

If I get it right, you only need to map some pattern texture to arbitrary shape room floor. This should not be the problem of generating texture, but of getting the right texture coordinates for each pixel. In this case you're drawing simple geometry (drawn as triangles). If your texture should not be somehow distorted (perspective, etc.) you can map triangle vector coordinates directly (or with some linear mapping) to texture coordinates with texture wrapping set to REPEAT or MIRROR (as you desire). What kind of graphical API (DirectX/OpenGL/other) are you using?

share|improve this answer
1  
He tagged his question with "Unity". He could use the Mesh class in unity to dynamically create meshes (including UV coordinates). –  bummzack Aug 13 '12 at 6:59
    
This doesn't answer my question; the issue is not my shape (or how I'm using it), it's the fact that the top of my texture has a row of transparent pixels while the bottom does not. Combining that fact with wrapmode.repeat gives the ugly artifacts. –  Raven Dreamer Aug 13 '12 at 22:47
add comment

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.