Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
[CustomEditor(typeof(MaterialScaleModifier))]
public class MaterialScaleModifierInspector : Editor
{
private MaterialScaleModifier _target;
private Renderer _renderer;
private Vector3 _scale;
private Texture2D _texture;
public override void OnInspectorGUI()
{
base.DrawDefaultInspector();
if(GUI.changed)
{
_target.ScaleTexture();
}
}
void OnEnable()
{
_target = (MaterialScaleModifier)target;
_renderer = _target.Renderer;
_scale = _target.transform.localScale;
_texture = (Texture2D)_renderer.sharedMaterial.mainTexture;
EditorApplication.update += OnUpdate;
}
void OnUpdate()
{
if(_target != null)
{
Vector3 scale = _target.transform.localScale;
Texture2D texture = (Texture2D)_renderer.sharedMaterial.mainTexture;
if (_scale != scale || _texture != texture)
{
_target.ScaleTexture();
_scale = scale;
_texture = texture;
}
}
}
void OnDisable()
{
EditorApplication.update -= OnUpdate;
_target = null;
}
}
#endif
public class MaterialScaleModifier : MonoBehaviour
{
public enum ScaleMode
{
Stretch,
Fit,
Crop
}
// serializables
[SerializeField]
private ScaleMode _scaleMode;
// properties
public Renderer Renderer
{
get
{
if(_renderer == null)
{
_renderer = GetComponent<Renderer>();
}
return _renderer;
}
}
// fields
private Renderer _renderer;
// MonoBehaviour
void Awake()
{
if(Renderer == null)
{
#if UNITY_EDITOR || DEVELOPMENT_BUILD
Debug.LogError("GameObject does not have a Renderer");
#endif
}
}
void Start()
{
ScaleTexture();
}
// Texture2dScaleMode
public void ScaleTexture()
{
if (Renderer != null &&
Renderer.sharedMaterial != null &&
Renderer.sharedMaterial.mainTexture != null)
{
Vector2 textureSize = GetTextureSize();
float rendererHeight = textureSize.x / GetRendererSizeRatio();
float rendererWidth = textureSize.y * GetRendererSizeRatio();
float diffWidth = rendererWidth - textureSize.x;
float diffHeight = rendererHeight - textureSize.y;
float diffMin = Mathf.Min(diffWidth, diffHeight);
float scaleX = 1.0f;
float scaleY = 1.0f;
float offsetX = 0;
float offsetY = 0;
TextureWrapMode wrapMode = TextureWrapMode.Repeat;
switch (_scaleMode)
{
case ScaleMode.Stretch:
// the default one, nothing to see here
break;
case ScaleMode.Fit: // scale to the smaller side
wrapMode = TextureWrapMode.Clamp;
if (diffMin == diffWidth)
{
ScaleToWidth(ref scaleY, ref offsetY);
}
else
{
ScaleToHeight(ref scaleX, ref offsetX);
}
break;
case ScaleMode.Crop: // scale to the larger side
if (diffMin == diffWidth)
{
ScaleToHeight(ref scaleX, ref offsetX);
}
else
{
ScaleToWidth(ref scaleY, ref offsetY);
}
break;
}
Renderer.sharedMaterial.mainTexture.wrapMode = wrapMode;
Renderer.sharedMaterial.mainTextureScale = new Vector2(scaleX, scaleY);
Renderer.sharedMaterial.mainTextureOffset = new Vector2(offsetX, offsetY);
}
}
private void ScaleToWidth(ref float scaleY, ref float offsetY)
{
Vector2 textureSize = GetTextureSize();
// if we maintain the image width
// get the object height assuming the object width is equal to the texture width
float rendererHeight = textureSize.x / GetRendererSizeRatio();
// get the corresponding percentage of the texture height inside the object height
scaleY = rendererHeight / textureSize.y;
// to center the image we would move it to the object height center minus half the image height
float offset = rendererHeight / 2 - textureSize.y / 2;
// get the corresponding percentage of the centering offset
offsetY = (offset * scaleY / rendererHeight) * -1;
}
private void ScaleToHeight(ref float scaleX, ref float offsetX)
{
Vector2 textureSize = GetTextureSize();
// if we maintain the image height
// get the object width assuming the object height is equal to the texture height
float rendererWidth = textureSize.y * GetRendererSizeRatio();
// get the corresponding percentage of the texture width inside the object width
scaleX = rendererWidth / textureSize.x;
// to center the image we would move it to the object width center minus half the image width
float offset = rendererWidth / 2 - textureSize.x / 2;
// get the corresponding percentage of the centering offset
offsetX = (offset * scaleX / rendererWidth) * -1;
}
private Renderer GetRenderer()
{
return GetComponent<Renderer>();
}
private Vector2 GetRendererSize()
{
return Renderer.bounds.size;
}
private float GetRendererSizeRatio()
{
float min = Mathf.Min(Renderer.bounds.size.x, Renderer.bounds.size.y, Renderer.bounds.size.z);
float ratio = 0;
if(min == Renderer.bounds.size.x)
{
ratio = Renderer.bounds.size.z / Renderer.bounds.size.y;
}
else if(min == Renderer.bounds.size.y)
{
ratio = Renderer.bounds.size.x / Renderer.bounds.size.z;
}
else
{
ratio = Renderer.bounds.size.x / Renderer.bounds.size.y;
}
return ratio;
}
private Vector2 GetTextureSize()
{
return new Vector2(Renderer.sharedMaterial.mainTexture.width, Renderer.sharedMaterial.mainTexture.height);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment