Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - Setsuki

Pages: [1]
Off-Topic / UNITY - Use your Tileset texture as a repeatable texture
« on: April 05, 2017, 12:08:20 PM »
I am currently using Crocotile to do models for my Unity project, and while it is near perfect for texture atlasing, there are performance gains to be had when you simply want to repeat one tile on a plane ; Using crocotile, this forces you to have a higher ploycount than a simple quad.

I have made a shader that repeats a tile over a basic Unity quad, in order to benefit from both texture atlasing and texture repeating, with a low polycount.

You can see the result in the linked file

Here is what you need :
RepeatTileTool.cs (anywhere in your project)
Code: [Select]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class RepeatTileTool : MonoBehaviour
    public Rect position;
    public Vector2 v2UnscaledRepeat =;
    public Vector2 v2PaddingInPixels =;
    // Use this for initialization
    void Awake () {

// Update is called once per frame
void Update () {
        if(!Application.isPlaying && Selection.activeGameObject == gameObject)
    /// <summary>
    /// we "hide" the informations about the tiling in the mesh
    /// </summary>
    void UpdateMesh()
        Mesh mesh = GetComponent<MeshFilter>().sharedMesh;
        Mesh newMesh = new Mesh();
        newMesh.vertices = mesh.vertices;
        newMesh.uv = mesh.uv;
        newMesh.triangles= mesh.triangles;
        newMesh.normals= mesh.normals;
        newMesh.tangents = mesh.tangents;
        Texture tex = GetComponent<MeshRenderer>().sharedMaterial.mainTexture;
        Vector2 v2Divided = new Vector2(position.width / tex.width , position.height / tex.height);

        //get the UVs corresponding to those
        float fUVxMin = v2Divided.x * position.x;
        float fUVxMax = (v2Divided.x * position.x) + v2Divided.x;
        float fUVyMax = 1- (v2Divided.y * position.y);
        float fUVyMin = 1-((v2Divided.y * position.y) + v2Divided.y);

        fUVxMin += v2PaddingInPixels.x /tex.width;
        fUVxMax -= v2PaddingInPixels.x / tex.width;
        fUVyMin += v2PaddingInPixels.y / tex.height;
        fUVyMax -= v2PaddingInPixels.y / tex.height;

        Vector2 [] v2RepeatToInput = new Vector2[mesh.vertexCount];
        Color [] colorsToInput = new Color[mesh.vertexCount];
        for (int i = 0; i < mesh.vertexCount; ++i)
            v2RepeatToInput[i] = new Vector2(v2UnscaledRepeat.x * transform.lossyScale.x, v2UnscaledRepeat.y * transform.lossyScale.y);
            colorsToInput[i] = new Color(fUVxMin, fUVxMax, fUVyMin, fUVyMax);
        newMesh.colors = colorsToInput;
        newMesh.uv2 = v2RepeatToInput;
        GetComponent<MeshFilter>().sharedMesh = newMesh;

RepeatTileInspector.cs (NEEDS to be in an "Editor" folder)
Code: [Select]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor( typeof( RepeatTileTool ) )]
public class RepeatTileInspector : Editor
private MeshRenderer m_renderer;
Texture2D m_editorTexture;
RepeatTileTool me;

public RepeatTileInspector()
Undo.undoRedoPerformed += RecalculateTexture;

public override void OnInspectorGUI()
me = ( RepeatTileTool )target;
if( m_renderer == null )
m_renderer = me.GetComponent<MeshRenderer>();

//if any changes is made, we remember it, as we'll need to redraw the texture
bool bChanged = false;

Undo.RecordObject( me, );
me.position = EditorGUILayout.RectField( "Position and size", me.position );

me.v2PaddingInPixels = EditorGUILayout.Vector2Field( "Padding (In pixels)", me.v2PaddingInPixels );

me.v2UnscaledRepeat = EditorGUILayout.Vector2Field( "Texture repeat per meter", me.v2UnscaledRepeat );

bChanged = EditorGUI.EndChangeCheck();

//draw the editor texture and add a square around the selected tile
if( m_editorTexture == null || bChanged )
//show the texture

int nPadding = 35;
int nWidth = Mathf.Min( Screen.width - nPadding, m_editorTexture.width - nPadding );
float fRatio = 1;
if( nWidth != m_editorTexture.width - nPadding )
//we're screen bound
fRatio = ( float )( Screen.width - nPadding ) / ( float )( m_editorTexture.width - nPadding );

Rect r = GUILayoutUtility.GetRect( nWidth, m_editorTexture.height * fRatio );
GUI.DrawTexture( r, ( m_editorTexture ), ScaleMode.ScaleToFit );


private void RecalculateTexture()
m_editorTexture = new Texture2D( m_renderer.sharedMaterial.mainTexture.width, m_renderer.sharedMaterial.mainTexture.height );
m_editorTexture.SetPixels( ( ( Texture2D )m_renderer.sharedMaterial.mainTexture ).GetPixels() );

Rect realPosition = new Rect( me.position.x * me.position.width, me.position.y * me.position.height, me.position.width, me.position.height );

for( int x = ( int )realPosition.xMin ; x < ( int )realPosition.xMax ; ++x )

m_editorTexture.SetPixel( x, m_editorTexture.height - ( int )realPosition.yMin, );
m_editorTexture.SetPixel( x, m_editorTexture.height - ( int )realPosition.yMax, );

for( int y = m_editorTexture.height - ( ( int )realPosition.yMax - 1 ) ; y < m_editorTexture.height - ( ( int )realPosition.yMin + 1 ) ; ++y )
m_editorTexture.SetPixel( ( int )realPosition.xMin, y, );
m_editorTexture.SetPixel( ( int )realPosition.xMax, y, );


realPosition.x += me.v2PaddingInPixels.x;
realPosition.width -= 2 * me.v2PaddingInPixels.x;
realPosition.y += me.v2PaddingInPixels.y;
realPosition.height -= 2 * me.v2PaddingInPixels.y;

for( int x = ( int )realPosition.xMin ; x < ( int )realPosition.xMax ; ++x )

m_editorTexture.SetPixel( x, m_editorTexture.height - ( int )realPosition.yMin, );
m_editorTexture.SetPixel( x, m_editorTexture.height - ( int )realPosition.yMax, );

for( int y = m_editorTexture.height - ( ( int )realPosition.yMax - 1 ) ; y < m_editorTexture.height - ( ( int )realPosition.yMin + 1 ) ; ++y )
m_editorTexture.SetPixel( ( int )realPosition.xMin, y, );
m_editorTexture.SetPixel( ( int )realPosition.xMax, y, );




RepeatTileShader.shader, anywhere in the project
Code: [Select]
Shader "Custom/Repeat Tile Shader" {
Properties {
_MainTex("Albedo (RGB)", 2D) = "white" {}
_FakeTex("Seriously?", 2D) = "white" {}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200

// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Lambert

// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0

sampler2D _MainTex;

struct Input {
float2 uv_MainTex;
float2 uv2_FakeTex;
float4 color : COLOR;
void surf (Input IN, inout SurfaceOutput o) {
//IN.uv2_FakeTex contains the repetition values
//IN.color contains the UVs of the tile we want to repeat

//uv are currently between 0 and 1. We make them between 0 and Repeat
IN.uv_MainTex.x *= IN.uv2_FakeTex.x;
//then, we remove the overflow to get it back between 0 and 1
IN.uv_MainTex.x -= floor(IN.uv_MainTex.x);

//We do the same with y
IN.uv_MainTex.y *= IN.uv2_FakeTex.y;
IN.uv_MainTex.y -= floor(IN.uv_MainTex.y);

IN.uv_MainTex.x = lerp(IN.color.r, IN.color.g, IN.uv_MainTex.x);
IN.uv_MainTex.y = lerp(IN.color.b, IN.color.a, IN.uv_MainTex.y);

fixed4 c = tex2Dlod (_MainTex, half4(IN.uv_MainTex.x,IN.uv_MainTex.y,0,0));

o.Albedo = c.rgb;
o.Alpha = c.a;
FallBack "Diffuse"

All you need to do now is :
Create a quad (GameObject/3D Object/Quad)
Apply a material using the Custom/Repeat Tile Shader shader, and using your tileset as texture
Add the component "RepeatTileTool" to the quad.
You should now see in your inspector your texture, and a simple editor to set the position, width and height of the rect you want to see on your quad. You can also set a pixel padding, and finally, a scaling tool.

Note : Due to visual issues, the shader doesn't use mipmaps. You can have mipmaps enabled, but the shader will ignore them.

Support / Re: REQUEST : UV offset
« on: March 31, 2017, 06:20:16 AM »
Thanks a lot, I should've mentioned it, my textures are indeed square and powers of two. (256x256 and 512x512 to be exact). But you are right, it is important for better rendering, especially on mobile.

Support / Re: REQUEST : UV offset
« on: March 11, 2017, 08:07:37 AM »
Thank you MrKarate, but I've been able to manage the problem in multiple ways, as this pixel precision requirement was giving me trouble with :
- Texture compression
- Anti-Aliasing
-Quality settings

Mixing multiple solutions of leaving an additional pixel for padding and shaders programmed for this purpose was the best solution, and actually gives me some room for mistake and low quality settings.

Support / Re: REQUEST : UV offset
« on: March 05, 2017, 04:54:53 PM »
Hello, and thank you.
The models are already redone, thanks to Crocotile's alt+click feature  ;D

Now, I can't set an UV padding if I don't export the textures. (The way you mentioned this option seemed to imply that it was possible.)
So I exported the texture as well.

I tried setting UV Padding to 1.

It doesn't look like the texture file exported is any different from the original.

Importing the model in Unity and using the generated tileset texture or the original texture doesn't change much ; The padding's been taken into account all right, but it's the opposite of the solution I'm looking for ; it expands the texture, while I'm trying to constrict it.

The way I did (using a 34x34 square for a 32x32 tile) works fine. We can agree that this is due to Unity's rendering...

Wait. :-[ I got it.

In case someone stumbles upon this thread looking for a solution. As you can guess, Crocotile exports the UVs and the model just fine. It is Unity that corrupts it.
Import your texture without compression (you probably already did this) but also, disable anti-aliasing. The glitch will be visible only if your camera is very, very close to the object.

Now I'm off to redo everything all over again. This is what versioning servers are for, kids.

Sorry Alex, this thread ends up not being in the right forum. Thank you for your answer and this software !

Support / REQUEST : UV offset
« on: March 05, 2017, 12:38:42 PM »
Hello !
I'm starting to use Crocotile recently for a personal game project, and I'm pretty glad I bought it so far.
However, I am encountering a problem, and while I found a workaround, I wonder if Crocotile would be able to provide tools to fix it.

In the attached files, image 1 is the tileset I'm using. Each tile is 32x32. image 2 is the resulting created object.

After exporting the object file and importing it to Unity, I encounter image 3 ; the UV precision isn't the same in crocotile and Unity, and despite tweaking shaders and import options, I keep having the same problem : the ploygons render with a tiny offset, and the alpha surrounding my tile "leaks" in my textured polygon.

I redid the whole tileset by making each tile 34x34 instead of 32x32, clamping each border, and setting an UV Padding of 1,1 in Crocotile. This way, I'm using a 32x32 tile and allow Unity an error of one pixel. As you can see in 4.png, it works.

Now, I have to remap ALL the models I did since my tileset has changed. And being a bit dumb, I did a lot of them before checking if everything worked properly.

So, I was wondering, to avoid future users from doing the same mistake I did, if there could be some ways to prevent this.

For example, allowing decimals in the UV Padding parameter, in order to only crop part of the border pixels ?
Or best of all, when exporting objects/scenes, have an "vertice UV padding" parameter, allowing the user to add this decimal padding at the last moment ?

Or maybe, just maybe, I'm thinking about this all wrong ?

Pages: [1]