using UnityEngine;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#if UNITY_5_3_OR_NEWER
using UnityEditor.SceneManagement;
#endif
#endif
namespace AutoTiling {
[ExecuteInEditMode]
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
///
/// Auto texture tiling.
/// --------------------
/// The base class of the Auto Texture Tiling Tool.
/// Just add this component to any GameObject with a Mesh (no Skinned Meshes yet, sorry), and it will keep the UV scaling relative to the object scaling.
///
/// This will NOT update the UV scaling while the game is running! Use DynamicTextureTiling instead.
///
public class AutoTextureTiling : MonoBehaviour {
public float faceUnwrappingNormalTolerance = 30f;
public bool useUnifiedScaling = false;
[SerializeField]
private Vector2 _topScale = Vector2.one;
[SerializeField]
private Vector2 _bottomScale = Vector2.one;
[SerializeField]
private Vector2 _leftScale = Vector2.one;
[SerializeField]
private Vector2 _rightScale = Vector2.one;
[SerializeField]
private Vector2 _frontScale = Vector2.one;
[SerializeField]
private Vector2 _backScale = Vector2.one;
public bool useUnifiedOffset = false;
[SerializeField]
private Vector2 _topOffset = Vector2.zero;
[SerializeField]
private Vector2 _bottomOffset = Vector2.zero;
[SerializeField]
private Vector2 _leftOffset = Vector2.zero;
[SerializeField]
private Vector2 _rightOffset = Vector2.zero;
[SerializeField]
private Vector2 _frontOffset = Vector2.zero;
[SerializeField]
private Vector2 _backOffset = Vector2.zero;
[SerializeField]
private float _topRotation = 0f;
[SerializeField]
private float _bottomRotation = 0f;
[SerializeField]
private float _leftRotation = 0f;
[SerializeField]
private float _rightRotation = 0f;
[SerializeField]
private float _frontRotation = 0f;
[SerializeField]
private float _backRotation = 0f;
[SerializeField]
private int _topMaterialIndex = 0;
[SerializeField]
private int _bottomMaterialIndex = 0;
[SerializeField]
private int _leftMaterialIndex = 0;
[SerializeField]
private int _rightMaterialIndex = 0;
[SerializeField]
private int _frontMaterialIndex = 0;
[SerializeField]
private int _backMaterialIndex = 0;
[SerializeField]
private bool _topFlipX = false;
[SerializeField]
private bool _topFlipY = false;
[SerializeField]
private bool _bottomFlipX = false;
[SerializeField]
private bool _bottomFlipY = false;
[SerializeField]
private bool _leftFlipX = false;
[SerializeField]
private bool _leftFlipY = false;
[SerializeField]
private bool _rightFlipX = false;
[SerializeField]
private bool _rightFlipY = false;
[SerializeField]
private bool _frontFlipX = false;
[SerializeField]
private bool _frontFlipY = false;
[SerializeField]
private bool _backFlipX = false;
[SerializeField]
private bool _backFlipY = false;
[SerializeField]
private bool _useBakedMesh;
[SerializeField]
protected FaceData[] _faceUnwrapData;
[SerializeField]
private UnwrapType _unwrapMethod = UnwrapType.FaceDependent;
[SerializeField]
private bool freshMesh = true;
protected float scaleX;
protected float scaleY;
protected float scaleZ;
private Mesh bakedSharedMeshAsset;
private MeshFilter _meshFilter;
private MeshRenderer meshRenderer;
private static string extensionString = ".asset";
private static string meshAssetPathString = "Assets/AutoTextureTilingTool/Meshes/";
public MeshRenderer Renderer {
get {
if (!meshRenderer) {
meshRenderer = GetComponent();
}
if (!meshRenderer) {
Debug.LogError(name + ": " + GetType() + ".Renderer_get: there was no MeshRenderer component attached.");
}
return meshRenderer;
}
}
public MeshFilter meshFilter {
get {
if (!_meshFilter) {
_meshFilter = GetComponent();
}
if (!_meshFilter) {
Debug.LogError(name + ": " + GetType() + ".meshFilter_get: there was no MeshFilter component attached.");
}
return _meshFilter;
}
}
public FaceData[] faceUnwrapData {
get {
return _faceUnwrapData;
}
}
public UnwrapType unwrapMethod {
get {
return _unwrapMethod;
}
set {
_unwrapMethod = value;
CreateMeshAndUVs();
}
}
#region CUBE_PROJECTION_PROPERTIES
public Vector2 topScale {
get {
return _topScale;
}
set {
_topScale = value;
CreateMeshAndUVs();
}
}
public Vector2 bottomScale {
get {
return _bottomScale;
}
set {
_bottomScale = value;
if (useUnifiedScaling) {
_topScale = value;
}
CreateMeshAndUVs();
}
}
public Vector2 leftScale {
get {
return _leftScale;
}
set {
_leftScale = value;
if (useUnifiedScaling) {
_topScale = value;
}
CreateMeshAndUVs();
}
}
public Vector2 rightScale {
get {
return _rightScale;
}
set {
_rightScale = value;
if (useUnifiedScaling) {
_topScale = value;
}
CreateMeshAndUVs();
}
}
public Vector2 frontScale {
get {
return _frontScale;
}
set {
_frontScale = value;
if (useUnifiedScaling) {
_topScale = value;
}
CreateMeshAndUVs();
}
}
public Vector2 backScale {
get {
return _backScale;
}
set {
_backScale = value;
if (useUnifiedScaling) {
_topScale = value;
}
CreateMeshAndUVs();
}
}
public Vector2 topOffset {
get {
return _topOffset;
}
set {
_topOffset = value;
CreateMeshAndUVs();
}
}
public Vector2 bottomOffset {
get {
return _bottomOffset;
}
set {
_bottomOffset = value;
if (useUnifiedOffset) {
_topOffset = value;
}
CreateMeshAndUVs();
}
}
public Vector2 leftOffset {
get {
return _leftOffset;
}
set {
_leftOffset = value;
if (useUnifiedOffset) {
_topOffset = value;
}
CreateMeshAndUVs();
}
}
public Vector2 rightOffset {
get {
return _rightOffset;
}
set {
_rightOffset = value;
if (useUnifiedOffset) {
_topOffset = value;
}
CreateMeshAndUVs();
}
}
public Vector2 frontOffset {
get {
return _frontOffset;
}
set {
_frontOffset = value;
if (useUnifiedOffset) {
_topOffset = value;
}
CreateMeshAndUVs();
}
}
public Vector2 backOffset {
get {
return _backOffset;
}
set {
_backOffset = value;
if (useUnifiedOffset) {
_topOffset = value;
}
CreateMeshAndUVs();
}
}
public float topRotation {
get {
return _topRotation;
}
set {
_topRotation = value;
CreateMeshAndUVs();
}
}
public float bottomRotation {
get {
return _bottomRotation;
}
set {
_bottomRotation = value;
CreateMeshAndUVs();
}
}
public float leftRotation {
get {
return _leftRotation;
}
set {
_leftRotation = value;
CreateMeshAndUVs();
}
}
public float rightRotation {
get {
return _rightRotation;
}
set {
_rightRotation = value;
CreateMeshAndUVs();
}
}
public float frontRotation {
get {
return _frontRotation;
}
set {
_frontRotation = value;
CreateMeshAndUVs();
}
}
public float backRotation {
get {
return _backRotation;
}
set {
_backRotation = value;
CreateMeshAndUVs();
}
}
public int topMaterialIndex {
get {
return _topMaterialIndex;
}
set {
_topMaterialIndex = value;
CreateMeshAndUVs();
}
}
public int bottomMaterialIndex {
get {
return _bottomMaterialIndex;
}
set {
_bottomMaterialIndex = value;
CreateMeshAndUVs();
}
}
public int leftMaterialIndex {
get {
return _leftMaterialIndex;
}
set {
_leftMaterialIndex = value;
CreateMeshAndUVs();
}
}
public int rightMaterialIndex {
get {
return _rightMaterialIndex;
}
set {
_rightMaterialIndex = value;
CreateMeshAndUVs();
}
}
public int frontMaterialIndex {
get {
return _frontMaterialIndex;
}
set {
_frontMaterialIndex = value;
CreateMeshAndUVs();
}
}
public int backMaterialIndex {
get {
return _backMaterialIndex;
}
set {
_backMaterialIndex = value;
CreateMeshAndUVs();
}
}
public bool topFlipX {
get {
return _topFlipX;
}
set {
_topFlipX = value;
CreateMeshAndUVs();
}
}
public bool topFlipY {
get {
return _topFlipY;
}
set {
_topFlipY = value;
CreateMeshAndUVs();
}
}
public bool bottomFlipX {
get {
return _bottomFlipX;
}
set {
_bottomFlipX = value;
CreateMeshAndUVs();
}
}
public bool bottomFlipY {
get {
return _bottomFlipY;
}
set {
_bottomFlipY = value;
CreateMeshAndUVs();
}
}
public bool leftFlipX {
get {
return _leftFlipX;
}
set {
_leftFlipX = value;
CreateMeshAndUVs();
}
}
public bool leftFlipY {
get {
return _leftFlipY;
}
set {
_leftFlipY = value;
CreateMeshAndUVs();
}
}
public bool rightFlipX {
get {
return _rightFlipX;
}
set {
_rightFlipX = value;
CreateMeshAndUVs();
}
}
public bool rightFlipY {
get {
return _rightFlipY;
}
set {
_rightFlipY = value;
CreateMeshAndUVs();
}
}
public bool frontFlipX {
get {
return _frontFlipX;
}
set {
_frontFlipX = value;
CreateMeshAndUVs();
}
}
public bool frontFlipY {
get {
return _frontFlipY;
}
set {
_frontFlipY = value;
CreateMeshAndUVs();
}
}
public bool backFlipX {
get {
return _backFlipX;
}
set {
_backFlipX = value;
CreateMeshAndUVs();
}
}
public bool backFlipY {
get {
return _backFlipY;
}
set {
_backFlipY = value;
CreateMeshAndUVs();
}
}
#endregion // CUBE_PROJECTION_PROPERTIES
public bool useBakedMesh {
get {
return _useBakedMesh;
}
set {
_useBakedMesh = value;
}
}
public virtual void Awake() {
_meshFilter = GetComponent();
if (!_meshFilter) {
Debug.LogError(name + ": " + GetType() + ".Awake: there was no MeshFilter component attached.");
}
meshRenderer = GetComponent();
if (!meshRenderer) {
Debug.LogError(name + ": " + GetType() + ".Awake: there was no MeshRenderer component attached.");
}
scaleX = transform.lossyScale.x;
scaleY = transform.lossyScale.y;
scaleZ = transform.lossyScale.z;
#if UNITY_EDITOR
if (Application.isPlaying && gameObject.isStatic) {
DestroyImmediate(this);
return;
}
else {
if (meshFilter.sharedMesh != null) {
if (!_useBakedMesh || !MeshPrefabExists()) {
Mesh meshCopy = Mesh.Instantiate(meshFilter.sharedMesh) as Mesh;
meshCopy.name = meshFilter.sharedMesh.name;
meshFilter.sharedMesh = meshCopy;
}
}
else {
_useBakedMesh = false;
Debug.Log(name + ": " + GetType() + ".CreateMeshAndUVs: there was no mesh, adding a default cube mesh.");
meshFilter.sharedMesh = new Mesh();
EditorUtility.SetDirty(this);
if (!Application.isPlaying) {
#if UNITY_5_3_OR_NEWER
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
#else
EditorApplication.MarkSceneDirty();
#endif
}
}
}
#endif
CreateMeshAndUVs();
}
// Updated only in the Editor, only if not in play mode. For Dynamic tiling at runtime use the DynamicTextureTiling component.
#if UNITY_EDITOR
void Update() {
if (!Application.isPlaying) {
if (scaleX != transform.lossyScale.x || scaleY != transform.lossyScale.y || scaleZ != transform.lossyScale.z) {
scaleX = transform.lossyScale.x;
scaleY = transform.lossyScale.y;
scaleZ = transform.lossyScale.z;
CreateMeshAndUVs();
}
if (meshFilter.sharedMesh == null) {
_useBakedMesh = false;
Debug.Log(name + ": " + GetType() + ".Update: there was no mesh, adding a default cube mesh.");
meshFilter.sharedMesh = new Mesh();
EditorUtility.SetDirty(this);
#if UNITY_5_3_OR_NEWER
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
#else
EditorApplication.MarkSceneDirty();
#endif
CreateMeshAndUVs();
}
}
}
#endif
public void AlignOffsetCenter(Direction side) {
switch (side) {
case Direction.Back:
backOffset = Vector2.zero;
break;
case Direction.Down:
bottomOffset = Vector2.zero;
break;
case Direction.Forward:
frontOffset = Vector2.zero;
break;
case Direction.Left:
leftOffset = Vector2.zero;
break;
case Direction.Right:
rightOffset = Vector2.zero;
break;
case Direction.Up:
topOffset = Vector2.zero;
break;
}
}
public void AlignOffsetCenter(int faceIndex) {
ApplyFaceOffset(faceIndex, Vector2.zero);
}
public void AlignOffsetTop(Direction side) {
switch (side) {
case Direction.Back:
backOffset = new Vector2(backOffset.x, 1f - (((transform.lossyScale.y - backScale.y) / backScale.y) * .5f));
break;
case Direction.Down:
bottomOffset = new Vector2(bottomOffset.x, 1f - (((transform.lossyScale.x - bottomScale.y) / bottomScale.y) * .5f));
break;
case Direction.Forward:
frontOffset = new Vector2(frontOffset.x, 1f - (((transform.lossyScale.y - frontScale.y) / frontScale.y) * .5f));
break;
case Direction.Left:
leftOffset = new Vector2(leftOffset.x, 1f - (((transform.lossyScale.y - leftScale.y) / leftScale.y) * .5f));
break;
case Direction.Right:
rightOffset = new Vector2(rightOffset.x, 1f - (((transform.lossyScale.y - rightScale.y) / rightScale.y) * .5f));
break;
case Direction.Up:
topOffset = new Vector2(topOffset.x, 1f - (((transform.lossyScale.x - topScale.y) / topScale.y) * .5f));
break;
}
}
public void AlignOffsetTop(int faceIndex) {
if (faceIndex < 0 || faceIndex >= _faceUnwrapData.Length) {
Debug.LogError(name + ": " + GetType() + ".ApplyFaceScale: faceIndex out of range: " + faceIndex);
return;
}
FaceData face = _faceUnwrapData[faceIndex];
Rect faceBounds = GetFaceBounds(face);
face.uvOffset = new Vector2(face.uvOffset.x, faceBounds.yMax / face.uvScale.y);
CreateMeshAndUVs();
}
public void AlignOffsetBottom(Direction side) {
switch (side) {
case Direction.Back:
backOffset = new Vector2(backOffset.x, ((transform.lossyScale.y - backScale.y) / backScale.y) * .5f);
break;
case Direction.Down:
bottomOffset = new Vector2(bottomOffset.x, ((transform.lossyScale.x - bottomScale.y) / bottomScale.y) * .5f);
break;
case Direction.Forward:
frontOffset = new Vector2(frontOffset.x, ((transform.lossyScale.y - frontScale.y) / frontScale.y) * .5f);
break;
case Direction.Left:
leftOffset = new Vector2(leftOffset.x, ((transform.lossyScale.y - leftScale.y) / leftScale.y) * .5f);
break;
case Direction.Right:
rightOffset = new Vector2(rightOffset.x, ((transform.lossyScale.y - rightScale.y) / rightScale.y) * .5f);
break;
case Direction.Up:
topOffset = new Vector2(topOffset.x, ((transform.lossyScale.x - topScale.y) / topScale.y) * .5f);
break;
}
}
public void AlignOffsetBottom(int faceIndex) {
if (faceIndex < 0 || faceIndex >= _faceUnwrapData.Length) {
Debug.LogError(name + ": " + GetType() + ".ApplyFaceScale: faceIndex out of range: " + faceIndex);
return;
}
FaceData face = _faceUnwrapData[faceIndex];
Rect faceBounds = GetFaceBounds(face);
face.uvOffset = new Vector2(face.uvOffset.x, faceBounds.y / face.uvScale.y);
CreateMeshAndUVs();
}
public void AlignOffsetLeft(Direction side) {
switch (side) {
case Direction.Back:
backOffset = new Vector2(((transform.lossyScale.x - backScale.x) / backScale.x) * .5f, backOffset.y);
break;
case Direction.Down:
bottomOffset = new Vector2(((1f - (transform.lossyScale.z - bottomScale.x) / bottomScale.x) * .5f), bottomOffset.y);
break;
case Direction.Forward:
frontOffset = new Vector2(((transform.lossyScale.x - frontScale.x) / frontScale.x) * .5f, frontOffset.y);
break;
case Direction.Left:
leftOffset = new Vector2(((transform.lossyScale.z - leftScale.x) / leftScale.x) * .5f, leftOffset.y);
break;
case Direction.Right:
rightOffset = new Vector2(((transform.lossyScale.z - rightScale.x) / rightScale.x) * .5f, rightOffset.y);
break;
case Direction.Up:
topOffset = new Vector2(((1f - (transform.lossyScale.z - topScale.x) / topScale.x) * .5f), topOffset.y);
break;
}
}
public void AlignOffsetLeft(int faceIndex) {
if (faceIndex < 0 || faceIndex >= _faceUnwrapData.Length) {
Debug.LogError(name + ": " + GetType() + ".ApplyFaceScale: faceIndex out of range: " + faceIndex);
return;
}
FaceData face = _faceUnwrapData[faceIndex];
Rect faceBounds = GetFaceBounds(face);
face.uvOffset = new Vector2(faceBounds.xMax / face.uvScale.x, face.uvOffset.y);
CreateMeshAndUVs();
}
public void AlignOffsetRight(Direction side) {
switch (side) {
case Direction.Back:
backOffset = new Vector2((1f - ((transform.lossyScale.x - backScale.x) / backScale.x) * .5f), backOffset.y);
break;
case Direction.Down:
bottomOffset = new Vector2((((transform.lossyScale.z - bottomScale.x) / bottomScale.x) * .5f), bottomOffset.y);
break;
case Direction.Forward:
frontOffset = new Vector2((1f - ((transform.lossyScale.x - frontScale.x) / frontScale.x) * .5f), frontOffset.y);
break;
case Direction.Left:
leftOffset = new Vector2((1f - ((transform.lossyScale.z - leftScale.x) / leftScale.x) * .5f), leftOffset.y);
break;
case Direction.Right:
rightOffset = new Vector2((1f - ((transform.lossyScale.z - rightScale.x) / rightScale.x) * .5f), rightOffset.y);
break;
case Direction.Up:
topOffset = new Vector2((((transform.lossyScale.z - topScale.x) / topScale.x) * .5f), topOffset.y);
break;
}
}
public void AlignOffsetRight(int faceIndex) {
if (faceIndex < 0 || faceIndex >= _faceUnwrapData.Length) {
Debug.LogError(name + ": " + GetType() + ".ApplyFaceScale: faceIndex out of range: " + faceIndex);
return;
}
FaceData face = _faceUnwrapData[faceIndex];
Rect faceBounds = GetFaceBounds(face);
face.uvOffset = new Vector2(faceBounds.x / face.uvScale.x, face.uvOffset.y);
CreateMeshAndUVs();
}
public void SetTextureToFit(Direction side) {
switch (side) {
case Direction.Back:
backOffset = Vector2.zero;
backRotation = 0f;
backScale = new Vector2(transform.lossyScale.x, transform.lossyScale.y);
break;
case Direction.Down:
bottomOffset = Vector2.zero;
bottomRotation = 0f;
bottomScale = new Vector2(transform.lossyScale.z, transform.lossyScale.x);
break;
case Direction.Forward:
frontOffset = Vector2.zero;
frontRotation = 0f;
frontScale = new Vector2(transform.lossyScale.x, transform.lossyScale.y);
break;
case Direction.Left:
leftOffset = Vector2.zero;
leftRotation = 0f;
leftScale = new Vector2(transform.lossyScale.z, transform.lossyScale.y);
break;
case Direction.Right:
rightOffset = Vector2.zero;
rightRotation = 0f;
rightScale = new Vector2(transform.lossyScale.z, transform.lossyScale.y);
break;
case Direction.Up:
topOffset = Vector2.zero;
topRotation = 0f;
topScale = new Vector2(transform.lossyScale.z, transform.lossyScale.x);
break;
}
}
public void SetTextureToFit(int faceIndex) {
if (faceIndex < 0 || faceIndex >= _faceUnwrapData.Length) {
Debug.LogError(name + ": " + GetType() + ".SetTextureToFit: faceIndex out of range: " + faceIndex);
return;
}
FaceData face = _faceUnwrapData[faceIndex];
Rect faceBounds = GetFaceBounds(face);
face.rotation = 0f;
face.uvScale = new Vector2(faceBounds.width, faceBounds.height);
face.uvOffset = new Vector2(faceBounds.center.x / face.uvScale.x, faceBounds.center.y / face.uvScale.y);
CreateMeshAndUVs();
}
public Rect GetFaceBounds(FaceData face) {
if (face == null) {
Debug.LogError(name + ": " + GetType() + ".GetFaceBounds: face was null.");
}
float minY = float.PositiveInfinity;
float maxY = float.NegativeInfinity;
float minX = float.PositiveInfinity;
float maxX = float.NegativeInfinity;
Quaternion rotationToTop = Quaternion.FromToRotation(Vector3.Scale(face.AverageNormal, transform.lossyScale), Vector3.up);
for (int t = 0; t < face.Triangles.Length; t++) {
Vector3 vector = meshFilter.sharedMesh.vertices[face.Triangles[t]];
Vector3 rotatedVector = rotationToTop * new Vector3(vector.x * transform.lossyScale.x, vector.y * transform.lossyScale.y, vector.z * transform.lossyScale.z);
if (rotatedVector.x < minX) {
minX = rotatedVector.x;
}
else if (rotatedVector.x > maxX) {
maxX = rotatedVector.x;
}
if (rotatedVector.z < minY) {
minY = rotatedVector.z;
}
else if (rotatedVector.z > maxY) {
maxY = rotatedVector.z;
}
}
return new Rect(minX, minY, maxX - minX, maxY - minY);
}
public void ApplyFlipUVX(int faceIndex, bool newFlipX) {
if (faceIndex < 0 || faceIndex >= _faceUnwrapData.Length) {
Debug.LogError(name + ": " + GetType() + ".ApplyFaceScale: faceIndex out of range: " + faceIndex);
return;
}
_faceUnwrapData[faceIndex].flipUVx = newFlipX;
CreateMeshAndUVs();
}
public void ApplyFlipUVY(int faceIndex, bool newFlipY) {
if (faceIndex < 0 || faceIndex >= _faceUnwrapData.Length) {
Debug.LogError(name + ": " + GetType() + ".ApplyFaceScale: faceIndex out of range: " + faceIndex);
return;
}
_faceUnwrapData[faceIndex].flipUVy = newFlipY;
CreateMeshAndUVs();
}
public void ApplyFaceMaterial(int faceIndex, int faceMaterialIndex) {
if (faceIndex < 0 || faceIndex >= _faceUnwrapData.Length) {
Debug.LogError(name + ": " + GetType() + ".ApplyFaceScale: faceIndex out of range: " + faceIndex);
return;
}
_faceUnwrapData[faceIndex].materialIndex = faceMaterialIndex;
CreateMeshAndUVs();
}
public void ApplyFaceOffset(int faceIndex, Vector2 offset) {
if (faceIndex < 0 || faceIndex >= _faceUnwrapData.Length) {
Debug.LogError(name + ": " + GetType() + ".ApplyFaceScale: faceIndex out of range: " + faceIndex);
return;
}
_faceUnwrapData[useUnifiedOffset ? 0 : faceIndex].uvOffset = offset;
CreateMeshAndUVs();
}
public void ApplyFaceRotation(int faceIndex, float rotation) {
if (faceIndex < 0 || faceIndex >= _faceUnwrapData.Length) {
Debug.LogError(name + ": " + GetType() + ".ApplyFaceScale: faceIndex out of range: " + faceIndex);
return;
}
_faceUnwrapData[faceIndex].rotation = rotation;
CreateMeshAndUVs();
}
public void ApplyFaceScale(int faceIndex, Vector2 scale) {
if (faceIndex < 0 || faceIndex >= _faceUnwrapData.Length) {
Debug.LogError(name + ": " + GetType() + ".ApplyFaceScale: faceIndex out of range: " + faceIndex);
return;
}
_faceUnwrapData[useUnifiedScaling ? 0 : faceIndex].uvScale = scale;
CreateMeshAndUVs();
}
public void CreateMeshAndUVs() {
if (meshFilter == null) {
Debug.LogError(GetType() + ".CreateMeshAndUVs: meshFilter was not set, there is no MeshFilter component attached.");
return;
}
#if UNITY_EDITOR
if (!meshFilter.sharedMesh)
{
Debug.LogError(GetType() + ".CreateMeshAndUVs: shared mesh was null. This should not happen.");
return;
}
if (!meshFilter.sharedMesh.isReadable) {
Debug.LogError(GetType() + ".CreateMeshAndUVs: could not edit mesh. Please make sure that 'Read/Write Enabled' is checked in the import settings.");
return;
}
#endif
MeshData meshData = new MeshData();
#if UNITY_EDITOR
Mesh meshToEdit;
if (_useBakedMesh)
{
if (!bakedSharedMeshAsset)
{
bakedSharedMeshAsset = AssetDatabase.LoadAssetAtPath(GetMeshAssetPath() + meshFilter.sharedMesh.name + extensionString, typeof(Mesh)) as Mesh;
}
meshToEdit = bakedSharedMeshAsset;
}
else
{
meshToEdit = Instantiate(meshFilter.sharedMesh);
}
meshToEdit.name = meshFilter.sharedMesh.name;
if (gameObject.isStatic && this as BasicTextureTiling == null)
{
Unwrapping.GenerateSecondaryUVSet(meshToEdit);
}
#else
Mesh meshToEdit = meshFilter.mesh;
if (meshToEdit == null)
{
Debug.LogWarning(GetType() + ".CreateMeshAndUVs: mesh was null. Automatically created a new one. Was this intended?");
meshToEdit = new Mesh();
}
#endif
if (meshToEdit.vertices.Length < 1) {
meshData = CreateStandardCubeMesh();
meshToEdit.subMeshCount = meshData.subMeshCount;
meshToEdit.vertices = meshData.Vertices.ToArray();
for (int i = 0; i < meshData.subMeshCount; i++) {
meshToEdit.SetTriangles(meshData.Triangles[i].ToArray(), i);
}
meshToEdit.uv = meshData.UV.ToArray();
meshToEdit.RecalculateBounds();
meshToEdit.RecalculateNormals();
#if UNITY_EDITOR
EditorUtility.SetDirty(meshFilter);
EditorUtility.SetDirty(this);
#endif
}
else {
Vector3[] oldVertices = meshToEdit.vertices;
Vector3[] oldNormals = meshToEdit.normals;
if (oldVertices.Length < 3) {
Debug.LogError(name + ": " + GetType() + ".CreateMeshAndUVs: there was something wrong with the mesh, not enough vertices: " + oldVertices.Length + ".");
return;
}
meshData.SetVertices(oldVertices);
if (oldNormals.Length != oldVertices.Length) {
Debug.LogError(name + ": " + GetType() + ".CreateMeshAndUVs: there was something wrong with the mesh, there were " + oldNormals.Length + " normals, but " + oldVertices.Length + " vertices. They need to have the same count.");
return;
}
meshData.SetNormals(oldNormals);
meshData.SetTriangles(meshToEdit);
meshData.SetTangents(meshToEdit.tangents);
meshData.SetUV2Coordinates(meshToEdit.uv2);
switch (_unwrapMethod) {
case UnwrapType.CubeProjection:
meshData = SplitMeshForCubeProjection(meshData);
break;
case UnwrapType.FaceDependent:
meshData = SplitMeshForFaceUnwrapping(meshData);
break;
default:
meshData = SplitMeshForFaceUnwrapping(meshData);
break;
}
// Copy modified meshdata to the object's mesh
meshToEdit.subMeshCount = meshData.subMeshCount;
if (meshData.Vertices.Count < meshToEdit.vertices.Length) {
for (int i = 0; i < meshData.subMeshCount; i++) {
if (meshData.Triangles[i].Count > 0 && meshData.Triangles[i].Count % 3 != 0) {
Debug.LogError(name + ": " + GetType() + ".CreateMeshAndUVs: there was something wrong with the mesh, triangles not divisible by 3. Triangles Count for material index " + i + ": " + meshData.Triangles[i].Count);
return;
}
meshToEdit.SetTriangles(meshData.Triangles[i].ToArray(), i);
}
meshToEdit.vertices = meshData.Vertices.ToArray();
}
else {
meshToEdit.vertices = meshData.Vertices.ToArray();
for (int i = 0; i < meshData.subMeshCount; i++) {
if (meshData.Triangles[i] == null) {
Debug.LogError(name + ": " + GetType() + ".CreateMeshAndUVs: there was something wrong with the mesh, triangles at " + i + " were null.");
continue;
}
else if (meshData.Triangles[i].Count > 0 && meshData.Triangles[i].Count % 3 != 0) {
Debug.LogError(name + ": " + GetType() + ".CreateMeshAndUVs: there was something wrong with the mesh, triangles not divisible by 3. Triangles Count for material index " + i + ": " + meshData.Triangles[i].Count);
continue;
}
meshToEdit.SetTriangles(meshData.Triangles[i].ToArray(), i);
}
}
meshToEdit.normals = meshData.Normals.ToArray();
meshToEdit.tangents = meshData.Tangents.ToArray();
meshToEdit.uv = meshData.UV.ToArray();
meshToEdit.uv2 = meshData.UV2.ToArray();
}
#if UNITY_EDITOR
if (!_useBakedMesh) {
#endif
meshToEdit.name = "Mesh " + name;
#if UNITY_EDITOR
}
#endif
#if UNITY_EDITOR
if (_useBakedMesh)
{
EditorUtility.SetDirty(meshToEdit);
}
else {
meshFilter.sharedMesh = meshToEdit;
}
#else
meshFilter.mesh = meshToEdit;
#endif
if (freshMesh) {
freshMesh = false;
}
}
private MeshData CreateStandardCubeMesh() {
MeshData meshData = new MeshData();
meshData.AddVertex(new Vector3(-0.5f, 0.5f, 0.5f));
meshData.AddVertex(new Vector3(0.5f, 0.5f, 0.5f));
meshData.AddVertex(new Vector3(0.5f, 0.5f, -0.5f));
meshData.AddVertex(new Vector3(-0.5f, 0.5f, -0.5f));
meshData.AddQuadTriangles();
meshData.AddUVCoordinates(QuadFaceUVs(Direction.Up));
meshData.AddVertex(new Vector3(-0.5f, -0.5f, -0.5f));
meshData.AddVertex(new Vector3(0.5f, -0.5f, -0.5f));
meshData.AddVertex(new Vector3(0.5f, -0.5f, 0.5f));
meshData.AddVertex(new Vector3(-0.5f, -0.5f, 0.5f));
meshData.AddQuadTriangles();
meshData.AddUVCoordinates(QuadFaceUVs(Direction.Down));
meshData.AddVertex(new Vector3(0.5f, -0.5f, 0.5f));
meshData.AddVertex(new Vector3(0.5f, 0.5f, 0.5f));
meshData.AddVertex(new Vector3(-0.5f, 0.5f, 0.5f));
meshData.AddVertex(new Vector3(-0.5f, -0.5f, 0.5f));
meshData.AddQuadTriangles();
meshData.AddUVCoordinates(QuadFaceUVs(Direction.Forward));
meshData.AddVertex(new Vector3(-0.5f, -0.5f, -0.5f));
meshData.AddVertex(new Vector3(-0.5f, 0.5f, -0.5f));
meshData.AddVertex(new Vector3(0.5f, 0.5f, -0.5f));
meshData.AddVertex(new Vector3(0.5f, -0.5f, -0.5f));
meshData.AddQuadTriangles();
meshData.AddUVCoordinates(QuadFaceUVs(Direction.Back));
meshData.AddVertex(new Vector3(-0.5f, -0.5f, 0.5f));
meshData.AddVertex(new Vector3(-0.5f, 0.5f, 0.5f));
meshData.AddVertex(new Vector3(-0.5f, 0.5f, -0.5f));
meshData.AddVertex(new Vector3(-0.5f, -0.5f, -0.5f));
meshData.AddQuadTriangles();
meshData.AddUVCoordinates(QuadFaceUVs(Direction.Left));
meshData.AddVertex(new Vector3(0.5f, -0.5f, -0.5f));
meshData.AddVertex(new Vector3(0.5f, 0.5f, -0.5f));
meshData.AddVertex(new Vector3(0.5f, 0.5f, 0.5f));
meshData.AddVertex(new Vector3(0.5f, -0.5f, 0.5f));
meshData.AddQuadTriangles();
meshData.AddUVCoordinates(QuadFaceUVs(Direction.Right));
return meshData;
}
private Vector2[] QuadFaceUVs(Direction dir) {
Vector2[] UVs = new Vector2[4];
float x = 1f;
float y = 1f;
switch (dir) {
case Direction.Up:
x = (transform.lossyScale.z / topScale.x);
y = (transform.lossyScale.x / topScale.y);
UVs[0] = new Vector2(x + topOffset.x, 0f + topOffset.y);
UVs[1] = new Vector2(x + topOffset.x, y + topOffset.y);
UVs[2] = new Vector2(0f + topOffset.x, y + topOffset.y);
UVs[3] = new Vector2(0f + topOffset.x, 0f + topOffset.y);
break;
case Direction.Down:
x = (transform.lossyScale.z / (useUnifiedScaling ? topScale.x : bottomScale.x));
y = (transform.lossyScale.x / (useUnifiedScaling ? topScale.y : bottomScale.y));
UVs[0] = new Vector2(x + (useUnifiedOffset ? topOffset.x : bottomOffset.x), 0f + (useUnifiedOffset ? topOffset.y : bottomOffset.y));
UVs[1] = new Vector2(x + (useUnifiedOffset ? topOffset.x : bottomOffset.x), y + (useUnifiedOffset ? topOffset.y : bottomOffset.y));
UVs[2] = new Vector2(0f + (useUnifiedOffset ? topOffset.x : bottomOffset.x), y + (useUnifiedOffset ? topOffset.y : bottomOffset.y));
UVs[3] = new Vector2(0f + (useUnifiedOffset ? topOffset.x : bottomOffset.x), 0f + (useUnifiedOffset ? topOffset.y : bottomOffset.y));
break;
case Direction.Left:
x = (transform.lossyScale.z / (useUnifiedScaling ? topScale.x : leftScale.x));
y = (transform.lossyScale.y / (useUnifiedScaling ? topScale.y : leftScale.y));
UVs[0] = new Vector2(x + (useUnifiedOffset ? topOffset.x : leftOffset.x), 0f + (useUnifiedOffset ? topOffset.y : leftOffset.y));
UVs[1] = new Vector2(x + (useUnifiedOffset ? topOffset.x : leftOffset.x), y + (useUnifiedOffset ? topOffset.y : leftOffset.y));
UVs[2] = new Vector2(0f + (useUnifiedOffset ? topOffset.x : leftOffset.x), y + (useUnifiedOffset ? topOffset.y : leftOffset.y));
UVs[3] = new Vector2(0f + (useUnifiedOffset ? topOffset.x : leftOffset.x), 0f + (useUnifiedOffset ? topOffset.y : leftOffset.y));
break;
case Direction.Right:
x = (transform.lossyScale.z / (useUnifiedScaling ? topScale.x : rightScale.x));
y = (transform.lossyScale.y / (useUnifiedScaling ? topScale.y : rightScale.y));
UVs[0] = new Vector2(x + (useUnifiedOffset ? topOffset.x : rightOffset.x), 0f + (useUnifiedOffset ? topOffset.y : rightOffset.y));
UVs[1] = new Vector2(x + (useUnifiedOffset ? topOffset.x : rightOffset.x), y + (useUnifiedOffset ? topOffset.y : rightOffset.y));
UVs[2] = new Vector2(0f + (useUnifiedOffset ? topOffset.x : rightOffset.x), y + (useUnifiedOffset ? topOffset.y : rightOffset.y));
UVs[3] = new Vector2(0f + (useUnifiedOffset ? topOffset.x : rightOffset.x), 0f + (useUnifiedOffset ? topOffset.y : rightOffset.y));
break;
case Direction.Forward:
x = (transform.lossyScale.x / (useUnifiedScaling ? topScale.x : frontScale.x));
y = (transform.lossyScale.y / (useUnifiedScaling ? topScale.y : frontScale.y));
UVs[0] = new Vector2(x + (useUnifiedOffset ? topOffset.x : frontOffset.x), 0f + (useUnifiedOffset ? topOffset.y : frontOffset.y));
UVs[1] = new Vector2(x + (useUnifiedOffset ? topOffset.x : frontOffset.x), y + (useUnifiedOffset ? topOffset.y : frontOffset.y));
UVs[2] = new Vector2(0f + (useUnifiedOffset ? topOffset.x : frontOffset.x), y + (useUnifiedOffset ? topOffset.y : frontOffset.y));
UVs[3] = new Vector2(0f + (useUnifiedOffset ? topOffset.x : frontOffset.x), 0f + (useUnifiedOffset ? topOffset.y : frontOffset.y));
break;
case Direction.Back:
x = (transform.lossyScale.x / (useUnifiedScaling ? topScale.x : backScale.x));
y = (transform.lossyScale.y / (useUnifiedScaling ? topScale.y : backScale.y));
UVs[0] = new Vector2(x + (useUnifiedOffset ? topOffset.x : backOffset.x), 0f + (useUnifiedOffset ? topOffset.y : backOffset.y));
UVs[1] = new Vector2(x + (useUnifiedOffset ? topOffset.x : backOffset.x), y + (useUnifiedOffset ? topOffset.y : backOffset.y));
UVs[2] = new Vector2(0f + (useUnifiedOffset ? topOffset.x : backOffset.x), y + (useUnifiedOffset ? topOffset.y : backOffset.y));
UVs[3] = new Vector2(0f + (useUnifiedOffset ? topOffset.x : backOffset.x), 0f + (useUnifiedOffset ? topOffset.y : backOffset.y));
break;
}
return UVs;
}
private MeshData SplitMeshForCubeProjection(MeshData data) {
// Debug.Log ("Old count vertices: " + data.Vertices.Count + ", old count UVs: " + data.UV.Count);
List topTriangles = new List();
List bottomTriangles = new List();
List leftTriangles = new List();
List rightTriangles = new List();
List frontTriangles = new List();
List backTriangles = new List();
for (int m = 0; m < data.Triangles.Length; m++) {
for (int i = 0; i < data.Triangles[m].Count; i += 3) {
// Debug.Log ("Handling triangle entry: " + i);
Vector3 triangleNormal = new Vector3();
List triangleVertIds = new List();
for (int tvId = 0; tvId < 3; tvId++) {
int index = data.Triangles[m][i + tvId];
triangleNormal += data.Normals[index];
triangleVertIds.Add(index);
}
Direction triangleNormalDirection = GetCubeProjectionDirectionForNormal(triangleNormal.normalized);
switch (triangleNormalDirection) {
case Direction.Back:
backTriangles.AddRange(triangleVertIds);
break;
case Direction.Down:
bottomTriangles.AddRange(triangleVertIds);
break;
case Direction.Forward:
frontTriangles.AddRange(triangleVertIds);
break;
case Direction.Left:
leftTriangles.AddRange(triangleVertIds);
break;
case Direction.Right:
rightTriangles.AddRange(triangleVertIds);
break;
case Direction.Up:
topTriangles.AddRange(triangleVertIds);
break;
}
}
}
MeshData newMeshData = new MeshData();
if (freshMesh) {
HashSet backTrianglesHashset = new HashSet();
for (int i = 0; i < backTriangles.Count; i++) {
backTrianglesHashset.Add(data.Vertices[backTriangles[i]]);
}
HashSet bottomTrianglesHashset = new HashSet();
for (int i = 0; i < bottomTriangles.Count; i++) {
bottomTrianglesHashset.Add(data.Vertices[bottomTriangles[i]]);
}
HashSet frontTrianglesHashset = new HashSet();
for (int i = 0; i < frontTriangles.Count; i++) {
frontTrianglesHashset.Add(data.Vertices[frontTriangles[i]]);
}
HashSet leftTrianglesHashset = new HashSet();
for (int i = 0; i < leftTriangles.Count; i++) {
leftTrianglesHashset.Add(data.Vertices[leftTriangles[i]]);
}
HashSet rightTrianglesHashset = new HashSet();
for (int i = 0; i < rightTriangles.Count; i++) {
rightTrianglesHashset.Add(data.Vertices[rightTriangles[i]]);
}
HashSet topTrianglesHashset = new HashSet();
for (int i = 0; i < topTriangles.Count; i++) {
topTrianglesHashset.Add(data.Vertices[topTriangles[i]]);
}
for (int i = 0; i < data.subMeshCount; i++) {
HashSet dataTrianglesHashset = new HashSet();
for (int j = 0; j < data.Triangles[i].Count; j++) {
dataTrianglesHashset.Add(data.Vertices[data.Triangles[i][j]]);
}
if (backTrianglesHashset.IsSubsetOf(dataTrianglesHashset)) {
_backMaterialIndex = i;
}
if (bottomTrianglesHashset.IsSubsetOf(dataTrianglesHashset)) {
_bottomMaterialIndex = i;
}
if (frontTrianglesHashset.IsSubsetOf(dataTrianglesHashset)) {
_frontMaterialIndex = i;
}
if (leftTrianglesHashset.IsSubsetOf(dataTrianglesHashset)) {
_leftMaterialIndex = i;
}
if (rightTrianglesHashset.IsSubsetOf(dataTrianglesHashset)) {
_rightMaterialIndex = i;
}
if (topTrianglesHashset.IsSubsetOf(dataTrianglesHashset)) {
_topMaterialIndex = i;
}
}
freshMesh = false;
}
newMeshData.subMeshCount = Mathf.Max(new int[] { _backMaterialIndex, _bottomMaterialIndex, _frontMaterialIndex, _leftMaterialIndex, _rightMaterialIndex, _topMaterialIndex }) + 1;
newMeshData = AddMeshDataForTriangleList(backTriangles, Vector3.back, newMeshData, data, _backMaterialIndex);
newMeshData = AddMeshDataForTriangleList(bottomTriangles, Vector3.down, newMeshData, data, _bottomMaterialIndex);
newMeshData = AddMeshDataForTriangleList(frontTriangles, Vector3.forward, newMeshData, data, _frontMaterialIndex);
newMeshData = AddMeshDataForTriangleList(leftTriangles, Vector3.left, newMeshData, data, _leftMaterialIndex);
newMeshData = AddMeshDataForTriangleList(rightTriangles, Vector3.right, newMeshData, data, _rightMaterialIndex);
newMeshData = AddMeshDataForTriangleList(topTriangles, Vector3.up, newMeshData, data, _topMaterialIndex);
return newMeshData;
}
protected virtual MeshData SplitMeshForFaceUnwrapping(MeshData meshData) {
MeshData oldMeshData = meshData.Copy();
meshData.RemoveDoubles(gameObject.isStatic);
List faceDataList = new List();
#region SORT_BY_FACE_NORMAL
for (int m = 0; m < meshData.Triangles.Length; m++) {
for (int i = 0; i < meshData.Triangles[m].Count; i += 3) {
bool addedToExistingFaceData = false;
int[] triangleVertexIndices = new int[3];
Vector3 triangleNormal = Vector3.zero;
for (int t = 0; t < 3; t++) {
triangleVertexIndices[t] = meshData.Triangles[m][i + t];
triangleNormal += meshData.Normals[triangleVertexIndices[t]];
}
triangleNormal /= 3f;
triangleNormal = new Vector3(triangleNormal.x / transform.lossyScale.x, triangleNormal.y / transform.lossyScale.y, triangleNormal.z / transform.lossyScale.z).normalized;
for (int faceIndex = 0; faceIndex < faceDataList.Count; faceIndex++) {
if (triangleNormal != Vector3.zero && faceDataList[faceIndex].IsWithinNormalAngleRange(triangleNormal, faceUnwrappingNormalTolerance)) {
faceDataList[faceIndex].AddTriangle(triangleVertexIndices, triangleNormal);
addedToExistingFaceData = true;
break;
}
}
if (!addedToExistingFaceData) {
FaceData newFaceData = new FaceData();
newFaceData.AddTriangle(triangleVertexIndices, triangleNormal);
faceDataList.Add(newFaceData);
}
}
}
#endregion //SORT_BY_FACE_NORMAL
#region SPLIT_FACES_BY_UV_EDGES
List splitFaceDataList = new List();
for (int i = 0; i < faceDataList.Count; i++) {
List triangles = new List(faceDataList[i].Triangles);
List> splitTriangles = new List>();
int currentIndex = 0;
int currentSplitTriangleIndex = 0;
splitTriangles.Add(new List());
while (triangles.Count > 0) {
if (splitTriangles[currentSplitTriangleIndex].Count < 1
|| splitTriangles[currentSplitTriangleIndex].Contains(triangles[currentIndex])
|| splitTriangles[currentSplitTriangleIndex].Contains(triangles[currentIndex + 1])
|| splitTriangles[currentSplitTriangleIndex].Contains(triangles[currentIndex + 2]))
{
splitTriangles[currentSplitTriangleIndex].Add(triangles[currentIndex]);
splitTriangles[currentSplitTriangleIndex].Add(triangles[currentIndex + 1]);
splitTriangles[currentSplitTriangleIndex].Add(triangles[currentIndex + 2]);
triangles.RemoveRange(currentIndex, 3);
currentIndex = 0;
}
else {
currentIndex += 3;
}
if (triangles.Count > 0 && currentIndex >= triangles.Count) {
currentIndex = 0;
splitTriangles.Add(new List());
currentSplitTriangleIndex++;
}
}
for (int splitI = 0; splitI < splitTriangles.Count; splitI++) {
if (splitTriangles[splitI].Count < 1) {
continue;
}
FaceData newData = new FaceData();
newData.CopySettingsFrom(faceDataList[i]);
for (int t = 0; t < splitTriangles[splitI].Count; t += 3) {
int[] triangleIndices = new int[3] { splitTriangles[splitI][t], splitTriangles[splitI][t + 1], splitTriangles[splitI][t + 2] };
Vector3 normal = Vector3.zero;
for (int tI = 0; tI < 3; tI++) {
normal += meshData.Normals[triangleIndices[tI]];
}
normal /= 3f;
newData.AddTriangle(triangleIndices, normal);
}
splitFaceDataList.Add(newData);
}
}
faceDataList = splitFaceDataList;
#endregion //SPLIT_FACES_BY_UV_EDGES
#region ADD_MESHDATA_FOR_FACEDATA
MeshData newMeshData = new MeshData();
newMeshData.subMeshCount = 1;
for (int newFaceDataIndex = 0; newFaceDataIndex < faceDataList.Count; newFaceDataIndex++) {
FaceData changedData = faceDataList[newFaceDataIndex];
newMeshData.subMeshCount = Mathf.Max(newMeshData.subMeshCount, faceDataList[newFaceDataIndex].materialIndex + 1);
newMeshData = AddMeshDataForFaceData(faceDataList[newFaceDataIndex], newMeshData, meshData, out changedData);
faceDataList[newFaceDataIndex] = changedData;
}
#endregion //ADD_MESHDATA_FOR_FACEDATA
#region ADD_UVDATA_FOR_FACEDATA
FaceData[] orderedFaceDataArray = new FaceData[faceDataList.Count];
List leftOverFaceData = new List();
for (int newFaceDataIndex = 0; newFaceDataIndex < faceDataList.Count; newFaceDataIndex++) {
if (_faceUnwrapData != null) {
for (int oldFaceDataIndex = 0; oldFaceDataIndex < _faceUnwrapData.Length; oldFaceDataIndex++) {
bool faceEqualsOldData = true;
if (_faceUnwrapData[oldFaceDataIndex] == null) {
_faceUnwrapData[oldFaceDataIndex] = new FaceData();
faceEqualsOldData = false;
}
else {
bool hadSimilarFace = false;
if (_faceUnwrapData[oldFaceDataIndex].Initialized && _faceUnwrapData[oldFaceDataIndex].Triangles != null && _faceUnwrapData[oldFaceDataIndex].Triangles.Length == faceDataList[newFaceDataIndex].Triangles.Length) {
hadSimilarFace = true;
List oldVertices = new List();
for (int i = 0; i < _faceUnwrapData[oldFaceDataIndex].Triangles.Length; i++) {
if (_faceUnwrapData[oldFaceDataIndex].Triangles[i] < newMeshData.Vertices.Count) {
oldVertices.Add(newMeshData.Vertices[_faceUnwrapData[oldFaceDataIndex].Triangles[i]]);
}
}
for (int iT = 0; iT < faceDataList[newFaceDataIndex].Triangles.Length; iT++) {
if (!oldVertices.Contains(newMeshData.Vertices[faceDataList[newFaceDataIndex].Triangles[iT]])) {
faceEqualsOldData = false;
break;
}
}
}
if (!hadSimilarFace) {
faceEqualsOldData = false;
}
}
if (faceEqualsOldData) {
faceDataList[newFaceDataIndex].Initialize(_faceUnwrapData[oldFaceDataIndex]);
if (oldFaceDataIndex < orderedFaceDataArray.Length) {
orderedFaceDataArray[oldFaceDataIndex] = faceDataList[newFaceDataIndex];
}
else {
leftOverFaceData.Add(faceDataList[newFaceDataIndex]);
}
break;
}
}
}
if (!faceDataList[newFaceDataIndex].Initialized) {
#region COPY_CUBE_PROJECTION_SETTINGS
switch (GetCubeProjectionDirectionForNormal(faceDataList[newFaceDataIndex].AverageNormal.normalized)) {
case Direction.Back:
faceDataList[newFaceDataIndex].flipUVx = backFlipX;
faceDataList[newFaceDataIndex].flipUVy = backFlipY;
faceDataList[newFaceDataIndex].materialIndex = backMaterialIndex;
faceDataList[newFaceDataIndex].rotation = backRotation;
faceDataList[newFaceDataIndex].uvOffset = backOffset;
faceDataList[newFaceDataIndex].uvScale = backScale;
break;
case Direction.Down:
faceDataList[newFaceDataIndex].flipUVx = bottomFlipX;
faceDataList[newFaceDataIndex].flipUVy = bottomFlipY;
faceDataList[newFaceDataIndex].materialIndex = bottomMaterialIndex;
faceDataList[newFaceDataIndex].rotation = bottomRotation;
faceDataList[newFaceDataIndex].uvOffset = bottomOffset;
faceDataList[newFaceDataIndex].uvScale = bottomScale;
break;
case Direction.Forward:
faceDataList[newFaceDataIndex].flipUVx = frontFlipX;
faceDataList[newFaceDataIndex].flipUVy = frontFlipY;
faceDataList[newFaceDataIndex].materialIndex = frontMaterialIndex;
faceDataList[newFaceDataIndex].rotation = frontRotation;
faceDataList[newFaceDataIndex].uvOffset = frontOffset;
faceDataList[newFaceDataIndex].uvScale = frontScale;
break;
case Direction.Left:
faceDataList[newFaceDataIndex].flipUVx = leftFlipX;
faceDataList[newFaceDataIndex].flipUVy = leftFlipY;
faceDataList[newFaceDataIndex].materialIndex = leftMaterialIndex;
faceDataList[newFaceDataIndex].rotation = leftRotation;
faceDataList[newFaceDataIndex].uvOffset = leftOffset;
faceDataList[newFaceDataIndex].uvScale = leftScale;
break;
case Direction.Right:
faceDataList[newFaceDataIndex].flipUVx = rightFlipX;
faceDataList[newFaceDataIndex].flipUVy = rightFlipY;
faceDataList[newFaceDataIndex].materialIndex = rightMaterialIndex;
faceDataList[newFaceDataIndex].rotation = rightRotation;
faceDataList[newFaceDataIndex].uvOffset = rightOffset;
faceDataList[newFaceDataIndex].uvScale = rightScale;
break;
case Direction.Up:
faceDataList[newFaceDataIndex].flipUVx = topFlipX;
faceDataList[newFaceDataIndex].flipUVy = topFlipY;
faceDataList[newFaceDataIndex].materialIndex = topMaterialIndex;
faceDataList[newFaceDataIndex].rotation = topRotation;
faceDataList[newFaceDataIndex].uvOffset = topOffset;
faceDataList[newFaceDataIndex].uvScale = topScale;
break;
}
#endregion
faceDataList[newFaceDataIndex].Initialize();
leftOverFaceData.Add(faceDataList[newFaceDataIndex]);
}
}
while (leftOverFaceData.Count > 0) {
for (int i = 0; i < orderedFaceDataArray.Length; i++) {
if (orderedFaceDataArray[i] == null) {
orderedFaceDataArray[i] = leftOverFaceData[0];
leftOverFaceData.RemoveAt(0);
break;
}
}
}
if (_faceUnwrapData != null) {
faceDataList = new List(orderedFaceDataArray);
}
// Check for old material indices and re-apply them where fitting
if (freshMesh) {
for (int subMeshIndex = 0; subMeshIndex < oldMeshData.subMeshCount; subMeshIndex++) {
HashSet subMeshTrianglesHash = new HashSet();
for (int i = 0; i < oldMeshData.Triangles[subMeshIndex].Count; i++) {
subMeshTrianglesHash.Add(oldMeshData.Vertices[oldMeshData.Triangles[subMeshIndex][i]]);
}
for (int fdIndex = 0; fdIndex < faceDataList.Count; fdIndex++) {
HashSet faceVerticesHash = new HashSet();
for (int i = 0; i < faceDataList[fdIndex].Triangles.Length; i++) {
faceVerticesHash.Add(newMeshData.Vertices[faceDataList[fdIndex].Triangles[i]]);
}
if (faceVerticesHash.IsSubsetOf(subMeshTrianglesHash)) {
//Debug.Log("Found fitting triangle mesh: setting material index to " + subMeshIndex);
faceDataList[fdIndex].materialIndex = subMeshIndex;
}
}
}
freshMesh = false;
}
MeshData updatedMeshData = new MeshData();
updatedMeshData.subMeshCount = 1;
for (int newFaceDataIndex = 0; newFaceDataIndex < faceDataList.Count; newFaceDataIndex++) {
FaceData changedData = new FaceData();
if (faceDataList[newFaceDataIndex] == null) {
faceDataList[newFaceDataIndex] = new FaceData();
faceDataList[newFaceDataIndex].Initialize();
}
updatedMeshData.subMeshCount = Mathf.Max(updatedMeshData.subMeshCount, faceDataList[newFaceDataIndex].materialIndex + 1);
updatedMeshData = AddMeshDataForFaceData(faceDataList[newFaceDataIndex], updatedMeshData, newMeshData, out changedData);
}
newMeshData = updatedMeshData;
#endregion //ADD_UVDATA_FOR_FACEDATA
_faceUnwrapData = faceDataList.ToArray();
return newMeshData;
}
private void LogFaceDataVertices(FaceData faceData, MeshData meshData) {
string vertexString = "";
if (faceData == null) {
vertexString += "(ERROR: faceData was null)";
}
else {
if (faceData.Triangles == null) {
vertexString = "(ERROR: faceData triangles were null)";
}
else {
for (int i = 0; i < faceData.Triangles.Length; i++) {
int index = faceData.Triangles[i];
if (index < meshData.Vertices.Count) {
vertexString += meshData.Vertices[index].ToString();
}
else {
vertexString += "(ERROR:" + index + " out of bound)";
}
}
}
}
Debug.Log(vertexString);
}
private MeshData AddMeshDataForTriangleList(List triangleIds, Vector3 normalDirection, MeshData newData, MeshData oldData, int materialIndex) {
Dictionary oldIdNewIdMapping = new Dictionary();
foreach (int vertId in triangleIds) {
if (!oldIdNewIdMapping.ContainsKey(vertId)) {
oldIdNewIdMapping[vertId] = newData.Vertices.Count;
newData.AddTriangle(newData.Vertices.Count, materialIndex);
newData.AddVertex(oldData.Vertices[vertId]);
if (vertId < oldData.Tangents.Count) {
newData.AddTangent(oldData.Tangents[vertId]);
}
newData.AddNormal(oldData.Normals[vertId]);
newData.AddUVCoordinate(VerticeUVByNormal(oldData.Vertices[vertId], normalDirection));
if (vertId < oldData.UV2.Count) {
newData.AddUV2Coordinate(oldData.UV2[vertId]);
}
}
else {
newData.AddTriangle(oldIdNewIdMapping[vertId], materialIndex);
}
}
return newData;
}
protected MeshData AddMeshDataForFaceData(FaceData faceData, MeshData newData, MeshData oldData, out FaceData updatedFaceData) {
Dictionary oldIdNewIdMapping = new Dictionary();
List newFaceTriangleIndices = new List();
foreach (int vertId in faceData.Triangles) {
if (!oldIdNewIdMapping.ContainsKey(vertId)) {
oldIdNewIdMapping[vertId] = newData.Vertices.Count;
newData.AddTriangle(newData.Vertices.Count, faceData.materialIndex);
newFaceTriangleIndices.Add(newData.Vertices.Count);
newData.AddVertex(oldData.Vertices[vertId]);
if (vertId < oldData.Tangents.Count) {
newData.AddTangent(oldData.Tangents[vertId]);
}
newData.AddNormal(oldData.Normals[vertId]);
newData.AddUVCoordinate(VerticeUVByFace(oldData.Vertices[vertId], faceData));
if (vertId < oldData.UV2.Count) {
newData.AddUV2Coordinate(oldData.UV2[vertId]);
}
}
else {
int index = oldIdNewIdMapping[vertId];
newData.AddTriangle(index, faceData.materialIndex);
newFaceTriangleIndices.Add(index);
}
}
faceData.SetTriangles(newFaceTriangleIndices.ToArray());
updatedFaceData = faceData;
return newData;
}
public static Direction GetCubeProjectionDirectionForNormal(Vector3 normal) {
Direction uvDir = Direction.Up;
float angle = Vector3.Angle(normal, Vector3.up);
float newAngle = Vector3.Angle(normal, Vector3.down);
if (newAngle < angle) {
angle = newAngle;
uvDir = Direction.Down;
}
newAngle = Vector3.Angle(normal, Vector3.left);
if (newAngle < angle) {
angle = newAngle;
uvDir = Direction.Left;
}
newAngle = Vector3.Angle(normal, Vector3.right);
if (newAngle < angle) {
angle = newAngle;
uvDir = Direction.Right;
}
newAngle = Vector3.Angle(normal, Vector3.forward);
if (newAngle < angle) {
angle = newAngle;
uvDir = Direction.Forward;
}
newAngle = Vector3.Angle(normal, Vector3.back);
if (newAngle < angle) {
angle = newAngle;
uvDir = Direction.Back;
}
return uvDir;
}
private Vector2 VerticeUVByNormal(Vector3 vertex, Vector3 normal) {
Direction uvDir = GetCubeProjectionDirectionForNormal(normal);
Vector2 uvCoord = new Vector2(1f, 1f);
switch (uvDir) {
case Direction.Up:
uvCoord = Quaternion.Euler(0f, 0f, topRotation) * new Vector2(transform.lossyScale.z * vertex.z, transform.lossyScale.x * vertex.x);
uvCoord.x = (uvCoord.x / topScale.x) + topOffset.x;
uvCoord.y = (uvCoord.y / topScale.y) + topOffset.y;
if (topFlipX) {
uvCoord.x = 1 - uvCoord.x;
}
if (topFlipY) {
uvCoord.y = 1 - uvCoord.y;
}
break;
case Direction.Down:
uvCoord = Quaternion.Euler(0f, 0f, bottomRotation) * new Vector2(transform.lossyScale.z * vertex.z, transform.lossyScale.x * vertex.x);
uvCoord.x = (uvCoord.x / (useUnifiedScaling ? topScale.x : bottomScale.x)) + (useUnifiedOffset ? topOffset.x : bottomOffset.x);
uvCoord.y = (uvCoord.y / (useUnifiedScaling ? topScale.y : bottomScale.y)) + (useUnifiedOffset ? topOffset.y : bottomOffset.y);
if (bottomFlipX) {
uvCoord.x = 1 - uvCoord.x;
}
if (bottomFlipY) {
uvCoord.y = 1 - uvCoord.y;
}
break;
case Direction.Left:
uvCoord = Quaternion.Euler(0f, 0f, leftRotation) * new Vector2(transform.lossyScale.z * vertex.z, transform.lossyScale.y * vertex.y);
uvCoord.x = (uvCoord.x / (useUnifiedScaling ? topScale.x : leftScale.x)) + (useUnifiedOffset ? topOffset.x : leftOffset.x);
uvCoord.y = (uvCoord.y / (useUnifiedScaling ? topScale.y : leftScale.y)) + (useUnifiedOffset ? topOffset.y : leftOffset.y);
if (leftFlipX) {
uvCoord.x = 1 - uvCoord.x;
}
if (leftFlipY) {
uvCoord.y = 1 - uvCoord.y;
}
break;
case Direction.Right:
uvCoord = Quaternion.Euler(0f, 0f, rightRotation) * new Vector2(transform.lossyScale.z * vertex.z, transform.lossyScale.y * vertex.y);
uvCoord.x = (uvCoord.x / (useUnifiedScaling ? topScale.x : rightScale.x)) + (useUnifiedOffset ? topOffset.x : rightOffset.x);
uvCoord.y = (uvCoord.y / (useUnifiedScaling ? topScale.y : rightScale.y)) + (useUnifiedOffset ? topOffset.y : rightOffset.y);
if (rightFlipX) {
uvCoord.x = 1 - uvCoord.x;
}
if (rightFlipY) {
uvCoord.y = 1 - uvCoord.y;
}
break;
case Direction.Forward:
uvCoord = Quaternion.Euler(0f, 0f, frontRotation) * new Vector2(transform.lossyScale.x * vertex.x, transform.lossyScale.y * vertex.y);
uvCoord.x = (uvCoord.x / (useUnifiedScaling ? topScale.x : frontScale.x)) + (useUnifiedOffset ? topOffset.x : frontOffset.x);
uvCoord.y = (uvCoord.y / (useUnifiedScaling ? topScale.y : frontScale.y)) + (useUnifiedOffset ? topOffset.y : frontOffset.y);
if (frontFlipX) {
uvCoord.x = 1 - uvCoord.x;
}
if (frontFlipY) {
uvCoord.y = 1 - uvCoord.y;
}
break;
case Direction.Back:
uvCoord = Quaternion.Euler(0f, 0f, backRotation) * new Vector2(transform.lossyScale.x * vertex.x, transform.lossyScale.y * vertex.y);
uvCoord.x = (uvCoord.x / (useUnifiedScaling ? topScale.x : backScale.x)) + (useUnifiedOffset ? topOffset.x : backOffset.x);
uvCoord.y = (uvCoord.y / (useUnifiedScaling ? topScale.y : backScale.y)) + (useUnifiedOffset ? topOffset.y : backOffset.y);
if (backFlipX) {
uvCoord.x = 1 - uvCoord.x;
}
if (backFlipY) {
uvCoord.y = 1 - uvCoord.y;
}
break;
}
return uvCoord;
}
private Vector2 VerticeUVByFace(Vector3 vertex, FaceData faceData) {
Vector3 normal = Vector3.Scale(faceData.AverageNormal, transform.lossyScale);
Vector3 localVertexCoord = Quaternion.FromToRotation(normal, Vector3.up) * new Vector3(vertex.x * transform.lossyScale.x, vertex.y * transform.lossyScale.y, vertex.z * transform.lossyScale.z);
Vector2 uvCoord = Quaternion.Euler(0f, 0f, faceData.rotation) * new Vector2(localVertexCoord.x, localVertexCoord.z);
uvCoord.x = (uvCoord.x / (useUnifiedScaling && _faceUnwrapData.Length > 0 && _faceUnwrapData[0] != null ? _faceUnwrapData[0].uvScale.x : faceData.uvScale.x))
+ (useUnifiedOffset && _faceUnwrapData.Length > 0 && _faceUnwrapData[0] != null ? _faceUnwrapData[0].uvOffset.x : faceData.uvOffset.x);
uvCoord.y = (uvCoord.y / (useUnifiedScaling && _faceUnwrapData.Length > 0 && _faceUnwrapData[0] != null ? _faceUnwrapData[0].uvScale.y : faceData.uvScale.y))
+ (useUnifiedOffset && _faceUnwrapData.Length > 0 && _faceUnwrapData[0] != null ? _faceUnwrapData[0].uvOffset.y : faceData.uvOffset.y);
if (faceData.flipUVx) {
uvCoord.x = 1 - uvCoord.x;
}
if (faceData.flipUVy) {
uvCoord.y = 1 - uvCoord.y;
}
return uvCoord;
}
#if UNITY_EDITOR
public void SaveMeshAsset() {
if (!meshFilter.sharedMesh) {
Debug.LogError(name + ": " + GetType() + ".SaveMeshAsset: there was no mesh set.");
return;
}
string currentMeshAssetPath = GetMeshAssetPath();
string[] pathParts = currentMeshAssetPath.Split('/');
if (pathParts == null || pathParts.Length < 1) {
Debug.LogError(GetType() + ".SaveMeshAsset: mesh asset path was set incorrectly.");
return;
}
if (pathParts[0] != "Assets") {
Debug.LogError(GetType() + ".SaveMeshAsset: mesh asset path has to start with \"Assets\".");
return;
}
for (int i = 1; i < pathParts.Length; i++) {
if (!string.IsNullOrEmpty(pathParts[i])) {
string currentPath = pathParts[0];
for (int curPathId = 1; curPathId < i; curPathId++) {
currentPath += "/" + pathParts[curPathId];
}
if (!AssetDatabase.IsValidFolder(currentPath + "/" + pathParts[i])) {
AssetDatabase.CreateFolder(currentPath, pathParts[i]);
}
}
}
Mesh meshPrefab = AssetDatabase.LoadAssetAtPath(currentMeshAssetPath + meshFilter.sharedMesh.name + extensionString, typeof(Mesh)) as Mesh;
if (meshPrefab) {
if (meshPrefab != meshFilter.sharedMesh) {
string[] meshNameParts = meshPrefab.name.Split('_');
if (meshNameParts.Length > 1) {
int numberSuffix = 0;
if (int.TryParse(meshNameParts[meshNameParts.Length - 1], out numberSuffix)) {
numberSuffix++;
string prefabName = currentMeshAssetPath + name + "_" + numberSuffix + extensionString;
// string prefabName = meshAssetPathString + EditorApplication.currentScene.Replace('/', '_').Replace('\\', '_') + "_" + name + "_" + numberSuffix + extensionString;
meshPrefab = AssetDatabase.LoadAssetAtPath(prefabName, typeof(Mesh)) as Mesh;
while (meshPrefab != null) {
prefabName = currentMeshAssetPath + name + "_" + (++numberSuffix) + extensionString;
// prefabName = meshAssetPathString + EditorApplication.currentScene.Replace('/', '_').Replace('\\', '_') + "_" + name + "_" + (++numberSuffix) + extensionString;
meshPrefab = AssetDatabase.LoadAssetAtPath(prefabName, typeof(Mesh)) as Mesh;
}
_useBakedMesh = true;
Mesh meshToSave = Mesh.Instantiate(meshFilter.sharedMesh);
meshToSave.name = meshFilter.sharedMesh.name;
AssetDatabase.CreateAsset(meshToSave, prefabName);
AssetDatabase.SaveAssets();
meshFilter.sharedMesh = AssetDatabase.LoadAssetAtPath(prefabName, typeof(Mesh)) as Mesh;
EditorUtility.SetDirty(meshFilter.sharedMesh);
EditorUtility.SetDirty(meshFilter);
EditorUtility.SetDirty(this);
}
}
else {
Debug.LogError(name + ": " + GetType() + ".SaveMeshAsset: prefab name " + meshPrefab.name + " has no number suffix.");
}
}
}
else {
int numberSuffix = 0;
string prefabName = currentMeshAssetPath + name + "_" + numberSuffix + extensionString;
// string prefabName = meshAssetPathString + EditorApplication.currentScene.Replace('/', '_').Replace('\\', '_') + "_" + name + "_" + numberSuffix + extensionString;
meshPrefab = AssetDatabase.LoadAssetAtPath(prefabName, typeof(Mesh)) as Mesh;
while (meshPrefab != null) {
prefabName = currentMeshAssetPath + name + "_" + (++numberSuffix) + extensionString;
// prefabName = meshAssetPathString + EditorApplication.currentScene.Replace('/', '_').Replace('\\', '_') + "_" + name + "_" + (++numberSuffix) + extensionString;
meshPrefab = AssetDatabase.LoadAssetAtPath(prefabName, typeof(Mesh)) as Mesh;
}
_useBakedMesh = true;
Mesh meshToSave = Mesh.Instantiate(meshFilter.sharedMesh);
meshToSave.name = meshFilter.sharedMesh.name;
AssetDatabase.CreateAsset(meshToSave, prefabName);
AssetDatabase.SaveAssets();
meshFilter.sharedMesh = AssetDatabase.LoadAssetAtPath(prefabName, typeof(Mesh)) as Mesh;
EditorUtility.SetDirty(meshFilter.sharedMesh);
EditorUtility.SetDirty(meshFilter);
EditorUtility.SetDirty(this);
}
}
public void DeleteConnectedMesh() {
string currentMeshAssetPath = GetMeshAssetPath();
Mesh meshPrefab = AssetDatabase.LoadAssetAtPath(currentMeshAssetPath + meshFilter.sharedMesh.name + extensionString, typeof(Mesh)) as Mesh;
if (!meshPrefab && meshFilter.sharedMesh.name.EndsWith("(Clone)")) {
meshPrefab = AssetDatabase.LoadAssetAtPath(currentMeshAssetPath + meshFilter.sharedMesh.name.Substring(0, meshFilter.sharedMesh.name.Length - 7) + extensionString, typeof(Mesh)) as Mesh;
}
if (meshPrefab) {
AutoTextureTiling[] listOfTextureTilingToolObjects = FindObjectsOfType();
for (int i = 0; i < listOfTextureTilingToolObjects.Length; i++) {
if (listOfTextureTilingToolObjects[i].meshFilter.sharedMesh == meshPrefab) {
listOfTextureTilingToolObjects[i].BreakMeshAssetConnection();
}
}
if (!AssetDatabase.DeleteAsset(currentMeshAssetPath + meshPrefab.name + extensionString)) {
Debug.LogError(name + ": " + GetType() + ".SaveMeshAsset: could not delete " + meshPrefab.name + ": failed to execute AssetDatabase.DeleteAsset.");
}
else {
GameObject prefab = PrefabUtility.GetCorrespondingObjectFromSource(this.gameObject) as GameObject;
if (prefab) {
Debug.LogWarning(GetType() + ".BreakMeshAssetConnection: mesh asset was deleted, but object was instance of a prefab. It is recommended to delete the prefab " + prefab.name + ".");
}
}
AssetDatabase.SaveAssets();
}
else {
_useBakedMesh = false;
EditorUtility.SetDirty(this);
Debug.LogError(name + ": " + GetType() + ".SaveMeshAsset: could not delete " + meshFilter.sharedMesh.name + ": Did not find the asset.");
}
}
public void BreakMeshAssetConnection() {
if (_useBakedMesh) {
if (meshFilter.sharedMesh) {
Mesh meshCopy = Mesh.Instantiate(meshFilter.sharedMesh) as Mesh;
meshCopy.name = meshFilter.sharedMesh.name;
meshFilter.sharedMesh = meshCopy;
meshFilter.sharedMesh.name = "Mesh " + name;
}
_useBakedMesh = false;
GameObject prefab = PrefabUtility.GetCorrespondingObjectFromSource(this.gameObject) as GameObject;
if (prefab)
{
#if UNITY_2018
PrefabUtility.UnpackPrefabInstance(this.gameObject, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
#else
PrefabUtility.DisconnectPrefabInstance(this.gameObject);
#endif
}
EditorUtility.SetDirty(this);
}
}
public bool MeshPrefabExists()
{
string currentMeshAssetPath = GetMeshAssetPath();
return AssetDatabase.LoadAssetAtPath(currentMeshAssetPath + meshFilter.sharedMesh.name + extensionString, typeof(Mesh)) as Mesh != null;
}
private string GetMeshAssetPath()
{
string currentMeshAssetPath = meshAssetPathString;
string[] pathGUIDs = AssetDatabase.FindAssets("AutoTextureTilingTool");
string foundPath = "";
if (pathGUIDs == null || pathGUIDs.Length < 1)
{
Debug.LogError("No asset \"AutoTextureTilingTool\" was found.");
}
else
{
if (pathGUIDs.Length > 1)
{
Debug.LogWarning(GetType() + ".SaveMeshAsset: there is more than one path or asset called \"AutoTextureTilingTool\". There should only be one single path named \"AutoTextureTilingTool\"");
}
for (int i = 0; i < pathGUIDs.Length; i++)
{
foundPath = AssetDatabase.GUIDToAssetPath(pathGUIDs[i]);
if (!string.IsNullOrEmpty(foundPath))
{
currentMeshAssetPath = foundPath + "/Meshes/";
break;
}
}
}
return currentMeshAssetPath;
}
#endif
#if FALSE // UNITY_EDITOR //
public void OnDrawGizmosSelected() {
if (faceUnwrapData == null) {
return;
}
if (!_meshFilter || !meshFilter.sharedMesh) {
return;
}
//for (int i = 0; i < meshFilter.sharedMesh.normals.Length; i++) {
// Vector3 startPos = meshFilter.sharedMesh.vertices[i];
// startPos = transform.position + transform.rotation * new Vector3(transform.lossyScale.x * startPos.x, transform.lossyScale.y * startPos.y, transform.lossyScale.z * startPos.z);
// Gizmos.color = Color.white;
// Gizmos.DrawLine(startPos, startPos + transform.rotation * meshFilter.sharedMesh.normals[i]);
//}
//for (int i = 0; i < _meshFilter.sharedMesh.triangles.Length; i += 3) {
// GL.PushMatrix();
// GL.Begin(GL.TRIANGLES);
// for (int j = 0; j < 3; j++) {
// GL.Color(Color.blue);
// int index = _meshFilter.sharedMesh.triangles[i + j];
// Vector3 currentVertex = _meshFilter.sharedMesh.vertices[index] + (_meshFilter.sharedMesh.normals[index] * 0.01f);
// GL.Vertex(transform.rotation * (new Vector3(currentVertex.x * transform.lossyScale.x, currentVertex.y * transform.lossyScale.y, currentVertex.z * transform.lossyScale.z)) + transform.position);
// }
// GL.End();
// GL.PopMatrix();
//}
for (int i = 0; i < faceUnwrapData.Length; i++) {
Vector3 averageFacePosition = Vector3.zero;
Vector3 averageNormal = Vector3.zero;
for (int v = 0; v < faceUnwrapData[i].Triangles.Length; v += 3) {
//GL.PushMatrix();
//GL.Begin(GL.TRIANGLES);
for (int j = 0; j < 3; j++) {
//GL.Color(new Color(((i) % 6) / 6f, ((2 + i) % 6) / 6f, ((4 + i) % 6) / 6f, 1f));
int index = faceUnwrapData[i].Triangles[v + j];
//Vector3 currentVertex = _meshFilter.sharedMesh.vertices[index] + (_meshFilter.sharedMesh.normals[index] * 0.01f);
//GL.Vertex(transform.rotation * (new Vector3(currentVertex.x * transform.lossyScale.x, currentVertex.y * transform.lossyScale.y, currentVertex.z * transform.lossyScale.z)) + transform.position);
if (index < _meshFilter.sharedMesh.vertices.Length) {
Vector3 newPos = _meshFilter.sharedMesh.vertices[index];
averageFacePosition += (transform.rotation *
new Vector3(newPos.x * transform.lossyScale.x, newPos.y * transform.lossyScale.y, newPos.z * transform.lossyScale.z));
averageNormal += _meshFilter.sharedMesh.normals[index];
}
else {
Debug.LogError("Index out of bound.");
}
}
//GL.End();
//GL.PopMatrix();
}
averageFacePosition = (averageFacePosition / (faceUnwrapData[i].Triangles.Length)) + transform.position;
averageNormal = transform.rotation * (averageNormal / (faceUnwrapData[i].Triangles.Length));
//Gizmos.DrawSphere(averageFacePosition, 0.1f);
Gizmos.color = Color.red;
Gizmos.DrawLine(averageFacePosition, averageFacePosition + averageNormal);
}
//for (int i = 0; i < faceUnwrapData.Length; i++) {
// Vector3 averageFacePosition = Vector3.zero;
// for (int v = 0; v < faceUnwrapData[i].Triangles.Length; v++) {
// int index = faceUnwrapData[i].Triangles[v];
// if (index < _meshFilter.sharedMesh.vertices.Length) {
// Vector3 newPos = _meshFilter.sharedMesh.vertices[index];
// averageFacePosition += (transform.rotation *
// new Vector3(newPos.x * transform.lossyScale.x, newPos.y * transform.lossyScale.y, newPos.z * transform.lossyScale.z));
// }
// else {
// Debug.LogError("Index out of bound.");
// }
// }
// averageFacePosition = (averageFacePosition / (faceUnwrapData[i].Triangles.Length)) + transform.position;
// Vector3 normal = new Vector3(faceUnwrapData[i].AverageNormal.x / transform.lossyScale.x, faceUnwrapData[i].AverageNormal.y / transform.lossyScale.y, faceUnwrapData[i].AverageNormal.z / transform.lossyScale.z).normalized;
// Vector3 normalEnd = averageFacePosition + (transform.rotation * normal);
// //Gizmos.DrawSphere(averageFacePosition, 0.1f);
// Gizmos.DrawLine(averageFacePosition, normalEnd);
//}
}
#endif
}
public enum Direction {
Up,
Down,
Left,
Right,
Forward,
Back,
}
[System.Serializable]
public class FaceData {
public Vector2 uvScale = Vector2.one;
public Vector2 uvOffset = Vector2.zero;
public float rotation = 0f;
public bool flipUVx = false;
public bool flipUVy = false;
public int materialIndex = 0;
[HideInInspector]
[SerializeField]
private int[] triangles;
[HideInInspector]
[SerializeField]
public Vector3[] normals;
[HideInInspector]
[SerializeField]
private Vector3 averageNormal;
[HideInInspector]
[SerializeField]
private bool initialized;
public Vector3 AverageNormal {
get {
return averageNormal;
}
}
public bool Initialized {
get {
return initialized;
}
}
public int[] Triangles {
get {
return triangles;
}
}
public FaceData() {
triangles = new int[0];
normals = new Vector3[0];
}
public void Initialize() {
initialized = true;
}
public void Initialize(FaceData dataForCopyingSettings) {
CopySettingsFrom(dataForCopyingSettings);
initialized = true;
}
public void CopySettingsFrom(FaceData dataForCopyingSettings) {
uvScale = dataForCopyingSettings.uvScale;
uvOffset = dataForCopyingSettings.uvOffset;
rotation = dataForCopyingSettings.rotation;
flipUVx = dataForCopyingSettings.flipUVx;
flipUVy = dataForCopyingSettings.flipUVy;
materialIndex = dataForCopyingSettings.materialIndex;
}
public void AddTriangle(int[] triangleVertexIndices, Vector3 normal) {
if (triangleVertexIndices == null) {
Debug.LogError(GetType() + ".AddTriangle: triangleVertexIndices was null.");
return;
}
if (triangleVertexIndices.Length != 3) {
Debug.LogError(GetType() + ".AddTriangle: triangle vertex index array has to have exactly 3 entries.");
return;
}
//Debug.Log("Adding Triangle: " + triangleVertexIndices[0] + "|" + triangleVertexIndices[1] + "|" + triangleVertexIndices[2]);
for (int i = 0; i < triangles.Length; i += 3) {
int sameIndexCount = 0;
for (int t = 0; t < 3; t++) {
if (triangles[i + t] == triangleVertexIndices[t]) {
sameIndexCount++;
}
}
if (sameIndexCount == 3) {
Debug.LogWarning(GetType() + ".AddTriangle: triangle " + triangleVertexIndices[0] + "|" + triangleVertexIndices[1] + "|" + triangleVertexIndices[2] + " already existed. Check your meshData.");
return;
}
}
int[] newVertexList = new int[triangles.Length + triangleVertexIndices.Length];
for (int i = 0; i < triangles.Length; i++) {
newVertexList[i] = triangles[i];
}
for (int i = 0; i < triangleVertexIndices.Length; i++) {
newVertexList[triangles.Length + i] = triangleVertexIndices[i];
}
triangles = newVertexList;
Vector3[] newNormals = new Vector3[normals.Length + 1];
averageNormal = Vector3.zero;
for (int i = 0; i < normals.Length; i++) {
newNormals[i] = normals[i];
averageNormal += normals[i];
}
newNormals[normals.Length] = normal;
averageNormal += normal;
averageNormal /= newNormals.Length;
normals = newNormals;
}
public bool IsWithinNormalAngleRange(Vector3 triangleNormal, float faceUnwrappingNormalTolerance) {
return Vector3.Angle(triangleNormal, averageNormal) <= faceUnwrappingNormalTolerance;
}
public void SetTriangles(int[] newFaceTriangleIndices) {
if (newFaceTriangleIndices == null) {
Debug.LogError(GetType() + ".SetTriangles: triangle index array can't be null.");
return;
}
if (newFaceTriangleIndices.Length % 3 != 0) {
Debug.LogError(GetType() + ".SetTriangles: triangle index array has to have a length devisable by 3. Array length: " + newFaceTriangleIndices.Length);
return;
}
triangles = newFaceTriangleIndices;
}
public string TrianglesToString() {
string returnString = "";
for (int i = 0; i < triangles.Length; i++) {
returnString += triangles[i].ToString();
if (i < triangles.Length - 1) {
returnString += ", ";
}
}
return returnString;
}
}
public enum UnwrapType {
CubeProjection,
FaceDependent,
}
}