Want to Make a Don't Starve Liked Tile Looking, Anyone Know how?

I don’t know if I should put this question here. I’m pretty new for Unity now.

For the beginning, I think the tile from Don’t starve using 2 type of texture to build its tile.

the first one is used for the shape of that tile like this below(I searched it from internet) but not like a pure mask, it contains a little lines for additional decorating the edge part.

And the second type of texture is used to fill the inside part and make it looks like a hand draw style.

They somehow blend those textures while keeping those dark lines from first one, keep and showing the hand draw texture from second one. Like this one below.

4286488--383911--upload_2019-3-6_11-39-48.png

For now, Here is what I did:

  1. I just imported 2 textures and divided them into a 3X3 pieces inside unity with the sprite editor. One for the shape, one for the inside texture.

  2. I wrote a simple shader which will show the provided texture if the color of that part is white. If not white, mix both texture by doing this"a.color.rgb * b.color.rgb".
    4286488--383920--upload_2019-3-6_11-48-6.png

So far everything looks fine.

  1. Here come the problem, the inside texture need to be independent from the shape. If you expand those tiles, there will be the same edge shape with different inside texture. However, they shape texture and the inside texture both get the same UV from the sprite I assigned(Which is the divided shape texture as above).

Is there anyway I can set the inside texture individually? Or is there any other idea to implement this function?

For now, I just think about to create 9 inside texture instead of 1, make 9 materials and assign them individually. It will be costy right?

Or is that possible to merge all those tiles’ shape textures in runtime and blend it with the inside texture? Will be that costy too?

Do anyone know how Don’t Starve achieve this function? That would be a great help for my work.

Thank you Guys so much.

Wow, I think unless I can merge all tiles into one sprite, the method I am trying now is too costy. Every tile will cause a draw call…

What you can do instead, is have the details texture (not the shape) be mapped over it using world position. This way if your texture properly tiles, it will always be continuous, and you can use a single shader and only swap out materials if you need different shapes.

Thank you for your reply. I will look into mapping it with world position thing. However, for each layer of the ground there will be multiple tiles, and each tile should have its own shape(which decided by its sprite/texture). How could I blend those shape textures and the detailed texture only with one shader?

I think you mean material in this case, not shader?
That would be rather tricky to be honest, and not really worth the trouble?
If you’re worried about draw calls, profile your project first and see how many calls exactly are spent on your terrain.

Yes, material. I blend the 2 textures in every tile, by add the corresponding material to each one. So each tile caused a draw call. I don’t think it’s acceptable. For now I am think about merge the shape texture together and use the merged shape texture to blend with the detailed texture. If this works, It may solve my problem.

Hmmm normally you should only get a draw call per material in the case of your tilemap, not per tile. Say you use 9 different shapes to fill a large floor of any number of tiles, assuming you use all materials you would get 9 calls.
Also, you could further reduce draw calls using this solution here: GPU Instancing with textures - Questions & Answers - Unity Discussions

In the shader I wrote, it does a blending operating. Might be the reason, it blend those two texture in every tile. Just guessing. I am new as a programmer, definitely I need to read through the Shader Book very soon. :stuck_out_tongue:

Yes, but the blending shouldn’t cause any additional draw calls unless you do the blending in a separate shader pass.
A draw call is caused whenever the CPU needs to send new information to the GPU. These can be textures, models, or material variables. If you have multiple objects with the exact same models and materials, they’ll be drawn in the same call.
Then, each shader creates more draw calls for each pass they have. 1 pass = 1 call.
Are you sure you’re getting a call per tile?

I am using the unity statistics to track the DC, I think for now DC is called “Batches” in that window.

While I am running the level and copying the tile, the batches will increased at the same time, same amount as those copies.

Here are the codes I used for my shader, I just get them from internet and modified them a little bit, deleted a lot of redundant functions.

Shader "Custom/MaskIcon" {
    Properties{
        _Maintex("Maintex", 2D) = "white" {}
        _BaseTex("BaseTex", 2D) = "white" {}

        [HideInInspector]_Cutoff("Alpha cutoff", Range(0,1)) = 0.5

        _Color("Tint", Color) = (1,1,1,1)


    }
        SubShader
        {
            LOD 200
            Tags
            {
                "IgnoreProjector" = "True"
                "Queue" = "Transparent"
                "RenderType" = "Transparent"
                "PreviewType" = "Plane"
                "CanUseSpriteAtlas" = "True"
            }

            Pass
            {
                Tags{
                "LightMode" = "ForwardBase"}
                Blend SrcAlpha OneMinusSrcAlpha
                ZWrite Off

                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "UnityCG.cginc"
                #pragma target 3.0
                uniform sampler2D _BaseTex; uniform float4 _BaseTex_ST;
                uniform sampler2D _Maintex; uniform float4 _Maintex_ST;
                fixed4 _Color;



                struct VertexInput {
                    float4 vertex : POSITION;
                    fixed4 color : COLOR;
                    fixed2 uv : TEXCOORD0;

                };
                struct VertexOutput {

                    fixed4 color : COLOR;
                    fixed2 texcoord : TEXCOORD0;
                    float4 vertex : SV_POSITION;
                };

                VertexOutput vert(VertexInput v) {
                    VertexOutput o = (VertexOutput)0;
                    o.color = v.color * _Color;

                    o.texcoord = v.uv;
                    o.vertex = UnityObjectToClipPos(v.vertex);

                    return o;
                }


                float4 frag(VertexOutput i) : COLOR{
                    ////// Lighting:
                    float4 _BaseTex_var = tex2D(_BaseTex,TRANSFORM_TEX(i.texcoord, _BaseTex));
                    float3 finalColor = _BaseTex_var.rgb;
                    float4 _Maintex_var = tex2D(_Maintex,TRANSFORM_TEX(i.texcoord, _Maintex));

                    _Maintex_var.rgb *= _Maintex_var.a;
                    if (_Maintex_var.r != 1 && _Maintex_var.g != 1 && _Maintex_var.b != 1)
                    {

                            finalColor.r = _Maintex_var.r * _BaseTex_var.r;
                            finalColor.g = _Maintex_var.g * _BaseTex_var.g;
                            finalColor.b = _Maintex_var.b * _BaseTex_var.b;
                       
                    }



                    return fixed4(finalColor, _Maintex_var.a) * _Color;
               

               
                }
           

                ENDCG
            }
        }
        FallBack "Diffuse"
}

I’m not seeing anything obviously wrong so far. Take a look at Unity’s page on Batching here.

OK,Thank you.

I tried to use Texture2D.SetPixel() to merge all tile by get every pixel and put it into the final one. Not possible, it’s too costy too. Try to find another way now.

Don’t make sprite atlases yourself, use Unity for it: Unity - Manual: Sprite Atlas properties reference

I will look into it. Thank you!

Today, I just get another idea, seems doable.

Use mesh to render those tile, and each mesh can hold multiple set of UV. I can change UV via script and put almost all texture into one sheet and reduce the drawcall.

BTW, thank for your mention yesterday, I found out why the draw call increased. I referred material in my script, even I didn’t use it. Unity will create a copy of that material once I refer it. Just because of one line of code like " Material xx = render.material;" One more draw call will be added to your pool.