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.


Topics - Setsuki

Pages: [1]
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;
#if UNITY_EDITOR
using UnityEditor;
#endif

[ExecuteInEditMode]
public class RepeatTileTool : MonoBehaviour
{
    public Rect position;
    public Vector2 v2UnscaledRepeat = Vector2.one;
    public Vector2 v2PaddingInPixels = Vector2.one;
    // Use this for initialization
    void Awake () {
        UpdateMesh();
}

// Update is called once per frame
void Update () {
#if UNITY_EDITOR
        if(!Application.isPlaying && Selection.activeGameObject == gameObject)
        {
            UpdateMesh();
        }
#endif
    }
    /// <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);


        //padding
        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;
EditorGUI.BeginChangeCheck();

Undo.RecordObject( me, me.name );
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 )
{
RecalculateTexture();
}
//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, Color.red );
m_editorTexture.SetPixel( x, m_editorTexture.height - ( int )realPosition.yMax, Color.red );
}


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, Color.red );
m_editorTexture.SetPixel( ( int )realPosition.xMax, y, Color.red );

}

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, Color.green );
m_editorTexture.SetPixel( x, m_editorTexture.height - ( int )realPosition.yMax, Color.green );
}


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, Color.green );
m_editorTexture.SetPixel( ( int )realPosition.xMax, y, Color.green );

}

m_editorTexture.Apply();
}

}

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

CGPROGRAM
// 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;
}
ENDCG
}
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.

2
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]