12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076 |
- //----------------------------------------------
- // MeshBaker
- // Copyright © 2011-2012 Ian Deane
- //----------------------------------------------
- using UnityEngine;
- using System.Collections;
- using System.IO;
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Reflection;
- /*
-
- Notes on Normal Maps in Unity3d
- Unity stores normal maps in a non standard format for some platforms. Think of the standard format as being english, unity's as being
- french. The raw image files in the project folder are in english, the AssetImporter converts them to french. Texture2D.GetPixels returns
- french. This is a problem when we build an atlas from Texture2D objects and save the result in the project folder.
- Unity wants us to flag this file as a normal map but if we do it is effectively translated twice.
- Solutions:
- 1) convert the normal map to english just before saving to project. Then set the normal flag and let the Importer do translation.
- This was rejected because Unity doesn't translate for all platforms. I would need to check with every version of Unity which platforms
- use which format.
- 2) Uncheck "normal map" on importer before bake and re-check after bake. This is the solution I am using.
- */
- namespace DigitalOpus.MB.Core
- {
- public class MB3_TextureCombinerPipeline
- {
- public static bool USE_EXPERIMENTAL_HOIZONTALVERTICAL = true;
- public struct CreateAtlasForProperty
- {
- public bool allTexturesAreNull;
- public bool allTexturesAreSame;
- public bool allNonTexturePropsAreSame;
- public override string ToString()
- {
- return String.Format("AllTexturesNull={0} areSame={1} nonTexPropsAreSame={2}", allTexturesAreNull, allTexturesAreSame, allNonTexturePropsAreSame);
- }
- }
- public static ShaderTextureProperty[] shaderTexPropertyNames = new ShaderTextureProperty[] {
- new ShaderTextureProperty("_MainTex",false),
- new ShaderTextureProperty("_BaseMap",false),
- new ShaderTextureProperty("_BaseColorMap",false),
- new ShaderTextureProperty("_BumpMap",true),
- new ShaderTextureProperty("_Normal",true),
- new ShaderTextureProperty("_BumpSpecMap",false),
- new ShaderTextureProperty("_DecalTex",false),
- new ShaderTextureProperty("_MaskMap",false),
- new ShaderTextureProperty("_BentNormalMap",false),
- new ShaderTextureProperty("_TangentMap",false),
- new ShaderTextureProperty("_AnisotropyMap",false),
- new ShaderTextureProperty("_SubsurfaceMaskMap",false),
- new ShaderTextureProperty("_ThicknessMap",false),
- new ShaderTextureProperty("_IridescenceThicknessMap",false),
- new ShaderTextureProperty("_IridescenceMaskMap",false),
- new ShaderTextureProperty("_SpecularColorMap",false),
- new ShaderTextureProperty("_EmissiveColorMap",false),
- new ShaderTextureProperty("_DistortionVectorMap",false),
- new ShaderTextureProperty("_TransmittanceColorMap",false),
- new ShaderTextureProperty("_Detail",false),
- new ShaderTextureProperty("_GlossMap",false),
- new ShaderTextureProperty("_Illum",false),
- new ShaderTextureProperty("_LightTextureB0",false),
- new ShaderTextureProperty("_ParallaxMap",false),
- new ShaderTextureProperty("_ShadowOffset",false),
- new ShaderTextureProperty("_TranslucencyMap",false),
- new ShaderTextureProperty("_SpecMap",false),
- new ShaderTextureProperty("_SpecGlossMap",false),
- new ShaderTextureProperty("_TranspMap",false),
- new ShaderTextureProperty("_MetallicGlossMap",false),
- new ShaderTextureProperty("_OcclusionMap",false),
- new ShaderTextureProperty("_EmissionMap",false),
- new ShaderTextureProperty("_DetailMask",false),
- // new ShaderTextureProperty("_DetailAlbedoMap",false),
- // new ShaderTextureProperty("_DetailNormalMap",true),
- };
- internal class TexturePipelineData
- {
- internal MB2_TextureBakeResults _textureBakeResults;
- internal int _atlasPadding = 1;
- internal int _maxAtlasWidth = 1;
- internal int _maxAtlasHeight = 1;
- internal bool _useMaxAtlasHeightOverride = false;
- internal bool _useMaxAtlasWidthOverride = false;
- internal bool _resizePowerOfTwoTextures = false;
- internal bool _fixOutOfBoundsUVs = false;
- internal int _maxTilingBakeSize = 1024;
- internal bool _saveAtlasesAsAssets = false;
- internal MB2_PackingAlgorithmEnum _packingAlgorithm = MB2_PackingAlgorithmEnum.UnitysPackTextures;
- internal bool _meshBakerTexturePackerForcePowerOfTwo = true;
- internal List<ShaderTextureProperty> _customShaderPropNames = new List<ShaderTextureProperty>();
- internal bool _normalizeTexelDensity = false;
- internal bool _considerNonTextureProperties = false;
- internal bool doMergeDistinctMaterialTexturesThatWouldExceedAtlasSize = false;
- internal MB3_TextureCombinerNonTextureProperties nonTexturePropertyBlender;
- internal List<MB_TexSet> distinctMaterialTextures;
- internal List<GameObject> allObjsToMesh;
- internal List<Material> allowedMaterialsFilter;
- internal List<ShaderTextureProperty> texPropertyNames;
- internal CreateAtlasForProperty[] allTexturesAreNullAndSameColor;
- internal MB2_TextureBakeResults.ResultType resultType;
- internal int numAtlases { get
- {
- if (texPropertyNames != null) return texPropertyNames.Count;
- else return 0;
- }
- }
- internal Material resultMaterial;
- internal bool OnlyOneTextureInAtlasReuseTextures()
- {
- if (distinctMaterialTextures != null &&
- distinctMaterialTextures.Count == 1 &&
- distinctMaterialTextures[0].thisIsOnlyTexSetInAtlas == true &&
- !_fixOutOfBoundsUVs &&
- !_considerNonTextureProperties)
- {
- return true;
- }
- return false;
- }
- }
- internal static bool _ShouldWeCreateAtlasForThisProperty(int propertyIndex, bool considerNonTextureProperties, CreateAtlasForProperty[] allTexturesAreNullAndSameColor)
- {
- CreateAtlasForProperty v = allTexturesAreNullAndSameColor[propertyIndex];
- if (considerNonTextureProperties)
- {
- if (!v.allNonTexturePropsAreSame || !v.allTexturesAreNull)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- if (!v.allTexturesAreNull)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- }
- internal static bool _CollectPropertyNames(MB3_TextureCombinerPipeline.TexturePipelineData data, MB2_LogLevel LOG_LEVEL)
- {
- return _CollectPropertyNames(data.texPropertyNames, data._customShaderPropNames,
- data.resultMaterial, LOG_LEVEL);
- }
- internal static bool _CollectPropertyNames(List<ShaderTextureProperty> texPropertyNames, List<ShaderTextureProperty> _customShaderPropNames,
- Material resultMaterial, MB2_LogLevel LOG_LEVEL)
- {
- //try custom properties remove duplicates
- for (int i = 0; i < texPropertyNames.Count; i++)
- {
- ShaderTextureProperty s = _customShaderPropNames.Find(x => x.name.Equals(texPropertyNames[i].name));
- if (s != null)
- {
- _customShaderPropNames.Remove(s);
- }
- }
- if (resultMaterial == null)
- {
- Debug.LogError("Please assign a result material. The combined mesh will use this material.");
- return false;
- }
- MBVersion.CollectPropertyNames(texPropertyNames, shaderTexPropertyNames, _customShaderPropNames, resultMaterial, LOG_LEVEL);
- return true;
- }
- private static bool _ShouldWeCreateAtlasForThisProperty(int propertyIndex, CreateAtlasForProperty[] allTexturesAreNullAndSameColor, TexturePipelineData data)
- {
- CreateAtlasForProperty v = allTexturesAreNullAndSameColor[propertyIndex];
- if (data._considerNonTextureProperties)
- {
- if (!v.allNonTexturePropsAreSame || !v.allTexturesAreNull)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- if (!v.allTexturesAreNull)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- }
- /// <summary>
- /// Some shaders like the Standard shader have texture properties like Emission which can be set on the material
- /// but are disabled using keywords. In these cases the textures should not be returned.
- /// </summary>
- public static Texture GetTextureConsideringStandardShaderKeywords(string shaderName, Material mat, string propertyName)
- {
- if (shaderName.Equals("Standard") || shaderName.Equals("Standard (Specular setup)") || shaderName.Equals("Standard (Roughness setup"))
- {
- if (propertyName.Equals("_EmissionMap"))
- {
- if (mat.IsKeywordEnabled("_EMISSION"))
- {
- return mat.GetTexture(propertyName);
- } else
- {
- return null;
- }
- }
- }
- return mat.GetTexture(propertyName);
- }
- /// <summary>
- /// Fills distinctMaterialTextures (a list of TexSets) and usedObjsToMesh. Each TexSet is a rectangle in the set of atlases.
- /// If allowedMaterialsFilter is empty then all materials on allObjsToMesh will be collected and usedObjsToMesh will be same as allObjsToMesh
- /// else only materials in allowedMaterialsFilter will be included and usedObjsToMesh will be objs that use those materials.
- /// bool __step1_CollectDistinctMatTexturesAndUsedObjects;
- /// </summary>
- internal virtual IEnumerator __Step1_CollectDistinctMatTexturesAndUsedObjects(ProgressUpdateDelegate progressInfo,
- MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult result,
- TexturePipelineData data,
- MB3_TextureCombiner combiner,
- MB2_EditorMethodsInterface textureEditorMethods,
- List<GameObject> usedObjsToMesh,
- MB2_LogLevel LOG_LEVEL
- )
- {
- System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
- sw.Start();
- // Collect distinct list of textures to combine from the materials on objsToCombine
- bool outOfBoundsUVs = false;
- Dictionary<int, MB_Utility.MeshAnalysisResult[]> meshAnalysisResultsCache = new Dictionary<int, MB_Utility.MeshAnalysisResult[]>(); //cache results
- for (int i = 0; i < data.allObjsToMesh.Count; i++)
- {
- GameObject obj = data.allObjsToMesh[i];
- if (progressInfo != null) progressInfo("Collecting textures for " + obj, ((float)i) / data.allObjsToMesh.Count / 2f);
- if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Collecting textures for object " + obj);
- if (obj == null)
- {
- Debug.LogError("The list of objects to mesh contained nulls.");
- result.success = false;
- yield break;
- }
- Mesh sharedMesh = MB_Utility.GetMesh(obj);
- if (sharedMesh == null)
- {
- Debug.LogError("Object " + obj.name + " in the list of objects to mesh has no mesh.");
- result.success = false;
- yield break;
- }
- Material[] sharedMaterials = MB_Utility.GetGOMaterials(obj);
- if (sharedMaterials.Length == 0)
- {
- Debug.LogError("Object " + obj.name + " in the list of objects has no materials.");
- result.success = false;
- yield break;
- }
- //analyze mesh or grab cached result of previous analysis, stores one result for each submesh
- MB_Utility.MeshAnalysisResult[] mar;
- if (!meshAnalysisResultsCache.TryGetValue(sharedMesh.GetInstanceID(), out mar))
- {
- mar = new MB_Utility.MeshAnalysisResult[sharedMesh.subMeshCount];
- for (int j = 0; j < sharedMesh.subMeshCount; j++)
- {
- MB_Utility.hasOutOfBoundsUVs(sharedMesh, ref mar[j], j);
- if (data._normalizeTexelDensity)
- {
- mar[j].submeshArea = GetSubmeshArea(sharedMesh, j);
- }
- if (data._fixOutOfBoundsUVs && !mar[j].hasUVs)
- {
- //assume UVs will be generated if this feature is being used and generated UVs will be 0,0,1,1
- mar[j].uvRect = new Rect(0, 0, 1, 1);
- Debug.LogWarning("Mesh for object " + obj + " has no UV channel but 'consider UVs' is enabled. Assuming UVs will be generated filling 0,0,1,1 rectangle.");
- }
- }
- meshAnalysisResultsCache.Add(sharedMesh.GetInstanceID(), mar);
- }
- if (data._fixOutOfBoundsUVs && LOG_LEVEL >= MB2_LogLevel.trace)
- {
- Debug.Log("Mesh Analysis for object " + obj + " numSubmesh=" + mar.Length + " HasOBUV=" + mar[0].hasOutOfBoundsUVs + " UVrectSubmesh0=" + mar[0].uvRect);
- }
- for (int matIdx = 0; matIdx < sharedMaterials.Length; matIdx++)
- { //for each submesh
- if (progressInfo != null) progressInfo(String.Format("Collecting textures for {0} submesh {1}", obj, matIdx), ((float)i) / data.allObjsToMesh.Count / 2f);
- Material mat = sharedMaterials[matIdx];
- //check if this material is in the list of source materaials
- if (data.allowedMaterialsFilter != null && !data.allowedMaterialsFilter.Contains(mat))
- {
- continue;
- }
- //Rect uvBounds = mar[matIdx].sourceUVRect;
- outOfBoundsUVs = outOfBoundsUVs || mar[matIdx].hasOutOfBoundsUVs;
- if (mat.name.Contains("(Instance)"))
- {
- Debug.LogError("The sharedMaterial on object " + obj.name + " has been 'Instanced'. This was probably caused by a script accessing the meshRender.material property in the editor. " +
- " The material to UV Rectangle mapping will be incorrect. To fix this recreate the object from its prefab or re-assign its material from the correct asset.");
- result.success = false;
- yield break;
- }
- if (data._fixOutOfBoundsUVs)
- {
- if (!MB_Utility.AreAllSharedMaterialsDistinct(sharedMaterials))
- {
- if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Object " + obj.name + " uses the same material on multiple submeshes. This may generate strange resultAtlasesAndRects especially when used with fix out of bounds uvs. Try duplicating the material.");
- }
- }
- //need to set up procedural material before converting its texs to texture2D
- /*
- if (mat is ProceduralMaterial)
- {
- combiner._addProceduralMaterial((ProceduralMaterial)mat);
- }
- */
- //collect textures scale and offset for each texture in objects material
- MeshBakerMaterialTexture[] mts = new MeshBakerMaterialTexture[data.texPropertyNames.Count];
- for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
- {
- Texture tx = null;
- Vector2 scale = Vector2.one;
- Vector2 offset = Vector2.zero;
- float texelDensity = 0f;
- int isImportedAsNormalMap = 0;
- if (mat.HasProperty(data.texPropertyNames[propIdx].name))
- {
- Texture txx = GetTextureConsideringStandardShaderKeywords(data.resultMaterial.shader.name, mat, data.texPropertyNames[propIdx].name);
- if (txx != null)
- {
- if (txx is Texture2D)
- {
- tx = txx;
- TextureFormat f = ((Texture2D)tx).format;
- bool isNormalMap = false;
- if (!Application.isPlaying && textureEditorMethods != null)
- {
- isNormalMap = textureEditorMethods.IsNormalMap((Texture2D)tx);
- isImportedAsNormalMap = isNormalMap == true ? -1 : 1;
- }
- if ((f == TextureFormat.ARGB32 ||
- f == TextureFormat.RGBA32 ||
- f == TextureFormat.BGRA32 ||
- f == TextureFormat.RGB24 ||
- f == TextureFormat.Alpha8) && !isNormalMap) //DXT5 does not work
- {
- //good
- }
- else
- {
- //TRIED to copy texture using tex2.SetPixels(tex1.GetPixels()) but bug in 3.5 means DTX1 and 5 compressed textures come out skewe
- if (Application.isPlaying && data._packingAlgorithm != MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Fast)
- {
- Debug.LogWarning("Object " + obj.name + " in the list of objects to mesh uses Texture " + tx.name + " uses format " + f + " that is not in: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 or DXT. These textures cannot be resized at runtime. Try changing texture format. If format says 'compressed' try changing it to 'truecolor'");
- result.success = false;
- yield break;
- }
- else
- {
- tx = (Texture2D)mat.GetTexture(data.texPropertyNames[propIdx].name);
- }
- }
- }
- /*
- else if (txx is ProceduralTexture)
- {
- //if (!MBVersion.IsTextureFormatRaw(((ProceduralTexture)txx).format))
- //{
- // Debug.LogError("Object " + obj.name + " in the list of objects to mesh uses a ProceduarlTexture that is not in a RAW format. Convert textures to RAW.");
- // result.success = false;
- // yield break;
- //}
- tx = txx;
- }
- */
- else
- {
- Debug.LogError("Object " + obj.name + " in the list of objects to mesh uses a Texture that is not a Texture2D. Cannot build atlases.");
- result.success = false;
- yield break;
- }
- }
- if (tx != null && data._normalizeTexelDensity)
- {
- //todo this doesn't take into account tiling and out of bounds UV sampling
- if (mar[propIdx].submeshArea == 0)
- {
- texelDensity = 0f;
- }
- else
- {
- texelDensity = (tx.width * tx.height) / (mar[propIdx].submeshArea);
- }
- }
- GetMaterialScaleAndOffset(mat, data.texPropertyNames[propIdx].name, out offset, out scale);
- }
- mts[propIdx] = new MeshBakerMaterialTexture(tx, offset, scale, texelDensity, isImportedAsNormalMap);
- }
- data.nonTexturePropertyBlender.CollectAverageValuesOfNonTextureProperties(data.resultMaterial, mat);
- Vector2 obUVscale = new Vector2(mar[matIdx].uvRect.width, mar[matIdx].uvRect.height);
- Vector2 obUVoffset = new Vector2(mar[matIdx].uvRect.x, mar[matIdx].uvRect.y);
- //Add to distinct set of textures if not already there
- MB_TextureTilingTreatment tilingTreatment = MB_TextureTilingTreatment.none;
- if (data._fixOutOfBoundsUVs)
- {
- tilingTreatment = MB_TextureTilingTreatment.considerUVs;
- }
- MB_TexSet setOfTexs = new MB_TexSet(mts, obUVoffset, obUVscale, tilingTreatment); //one of these per submesh
- MatAndTransformToMerged matt = new MatAndTransformToMerged(new DRect(obUVoffset, obUVscale), data._fixOutOfBoundsUVs, mat);
- setOfTexs.matsAndGOs.mats.Add(matt);
- MB_TexSet setOfTexs2 = data.distinctMaterialTextures.Find(x => x.IsEqual(setOfTexs, data._fixOutOfBoundsUVs, data.nonTexturePropertyBlender));
- if (setOfTexs2 != null)
- {
- setOfTexs = setOfTexs2;
- }
- else
- {
- data.distinctMaterialTextures.Add(setOfTexs);
- }
- if (!setOfTexs.matsAndGOs.mats.Contains(matt))
- {
- setOfTexs.matsAndGOs.mats.Add(matt);
- }
- if (!setOfTexs.matsAndGOs.gos.Contains(obj))
- {
- setOfTexs.matsAndGOs.gos.Add(obj);
- if (!usedObjsToMesh.Contains(obj)) usedObjsToMesh.Add(obj);
- }
- }
- }
- if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log(String.Format("Step1_CollectDistinctTextures collected {0} sets of textures fixOutOfBoundsUV={1} considerNonTextureProperties={2}", data.distinctMaterialTextures.Count, data._fixOutOfBoundsUVs, data._considerNonTextureProperties));
- if (data.distinctMaterialTextures.Count == 0)
- {
- string[] filterStrings = new string[data.allowedMaterialsFilter.Count];
- for (int i = 0; i < filterStrings.Length; i++) filterStrings[i] = data.allowedMaterialsFilter[i].name;
- string allowedMaterialsString = string.Join(", ", filterStrings);
- Debug.LogError("None of the source object materials matched any of the allowed materials for submesh with result material: " + data.resultMaterial + " allowedMaterials: " + allowedMaterialsString);
- result.success = false;
- yield break;
- }
- MB3_TextureCombinerMerging merger = new MB3_TextureCombinerMerging(data._considerNonTextureProperties, data.nonTexturePropertyBlender, data._fixOutOfBoundsUVs, LOG_LEVEL);
- merger.MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(data.distinctMaterialTextures);
- if (data.doMergeDistinctMaterialTexturesThatWouldExceedAtlasSize)
- {
- merger.MergeDistinctMaterialTexturesThatWouldExceedMaxAtlasSizeAndCalcMaterialSubrects(data.distinctMaterialTextures, Mathf.Max(data._maxAtlasHeight, data._maxAtlasWidth));
- }
- // Try to guess the isNormalMap if for textureProperties if necessary.
- {
- for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
- {
- ShaderTextureProperty texProp = data.texPropertyNames[propIdx];
- if (texProp.isNormalDontKnow)
- {
- int isNormalVote = 0;
- for (int rectIdx = 0; rectIdx < data.distinctMaterialTextures.Count; rectIdx++)
- {
- MeshBakerMaterialTexture matTex = data.distinctMaterialTextures[rectIdx].ts[propIdx];
- isNormalVote += matTex.isImportedAsNormalMap;
- }
- texProp.isNormalMap = isNormalVote >= 0 ? false : true;
- texProp.isNormalDontKnow = false;
- }
- }
- }
- if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Total time Step1_CollectDistinctTextures " + (sw.ElapsedMilliseconds).ToString("f5"));
- yield break;
- }
- private static CreateAtlasForProperty[] CalculateAllTexturesAreNullAndSameColor(MB3_TextureCombinerPipeline.TexturePipelineData data, MB2_LogLevel LOG_LEVEL)
- {
- // check if all textures are null and use same color for each atlas
- // will not generate an atlas if so
- CreateAtlasForProperty[] shouldWeCreateAtlasForProp = new CreateAtlasForProperty[data.texPropertyNames.Count];
- for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
- {
- MeshBakerMaterialTexture firstTexture = data.distinctMaterialTextures[0].ts[propIdx];
- Color firstColor = Color.black;
- if (data._considerNonTextureProperties)
- {
- firstColor = data.nonTexturePropertyBlender.GetColorAsItWouldAppearInAtlasIfNoTexture(data.distinctMaterialTextures[0].matsAndGOs.mats[0].mat, data.texPropertyNames[propIdx]);
- }
- int numTexturesExisting = 0;
- int numTexturesMatchinFirst = 0;
- int numNonTexturePropertiesMatchingFirst = 0;
- for (int j = 0; j < data.distinctMaterialTextures.Count; j++)
- {
- if (!data.distinctMaterialTextures[j].ts[propIdx].isNull)
- {
- numTexturesExisting++;
- }
- if (firstTexture.AreTexturesEqual(data.distinctMaterialTextures[j].ts[propIdx]))
- {
- numTexturesMatchinFirst++;
- }
- if (data._considerNonTextureProperties)
- {
- Color colJ = data.nonTexturePropertyBlender.GetColorAsItWouldAppearInAtlasIfNoTexture(data.distinctMaterialTextures[j].matsAndGOs.mats[0].mat, data.texPropertyNames[propIdx]);
- if (colJ == firstColor)
- {
- numNonTexturePropertiesMatchingFirst++;
- }
- }
- }
- shouldWeCreateAtlasForProp[propIdx].allTexturesAreNull = numTexturesExisting == 0;
- shouldWeCreateAtlasForProp[propIdx].allTexturesAreSame = numTexturesMatchinFirst == data.distinctMaterialTextures.Count;
- shouldWeCreateAtlasForProp[propIdx].allNonTexturePropsAreSame = numNonTexturePropertiesMatchingFirst == data.distinctMaterialTextures.Count;
- if (LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log(String.Format("AllTexturesAreNullAndSameColor prop: {0} createAtlas:{1} val:{2}", data.texPropertyNames[propIdx].name, MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, shouldWeCreateAtlasForProp), shouldWeCreateAtlasForProp[propIdx]));
- }
- return shouldWeCreateAtlasForProp;
- }
- //Textures in each material (_mainTex, Bump, Spec ect...) must be same size
- //Calculate the best sized to use. Takes into account tiling
- //if only one texture in atlas re-uses original sizes
- internal virtual IEnumerator CalculateIdealSizesForTexturesInAtlasAndPadding(ProgressUpdateDelegate progressInfo,
- MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult result,
- MB3_TextureCombinerPipeline.TexturePipelineData data,
- MB3_TextureCombiner combiner,
- MB2_EditorMethodsInterface textureEditorMethods,
- MB2_LogLevel LOG_LEVEL)
- {
- System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
- sw.Start();
- MeshBakerMaterialTexture.readyToBuildAtlases = true;
- data.allTexturesAreNullAndSameColor = CalculateAllTexturesAreNullAndSameColor(data, LOG_LEVEL);
- //calculate size of rectangles in atlas
- int _padding = data._atlasPadding;
- if (data.distinctMaterialTextures.Count == 1 && data._fixOutOfBoundsUVs == false && data._considerNonTextureProperties == false)
- {
- if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("All objects use the same textures in this set of atlases. Original textures will be reused instead of creating atlases.");
- _padding = 0;
- data.distinctMaterialTextures[0].SetThisIsOnlyTexSetInAtlasTrue();
- data.distinctMaterialTextures[0].SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(MB_TextureTilingTreatment.edgeToEdgeXY);
- }
- Debug.Assert(data.allTexturesAreNullAndSameColor.Length == data.texPropertyNames.Count, "allTexturesAreNullAndSameColor array must be the same length of texPropertyNames.");
- for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
- {
- if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Calculating ideal sizes for texSet TexSet " + i + " of " + data.distinctMaterialTextures.Count);
- MB_TexSet txs = data.distinctMaterialTextures[i];
- txs.idealWidth = 1;
- txs.idealHeight = 1;
- int tWidth = 1;
- int tHeight = 1;
- Debug.Assert(txs.ts.Length == data.texPropertyNames.Count, "length of arrays in each element of distinctMaterialTextures must be texPropertyNames.Count");
- //get the best size all textures in a TexSet must be the same size.
- for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
- {
- if (MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
- {
- MeshBakerMaterialTexture matTex = txs.ts[propIdx];
- if (LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log(string.Format("Calculating ideal size for texSet {0} property {1}", i, data.texPropertyNames[propIdx].name));
- if (!matTex.matTilingRect.size.Equals(Vector2.one) && data.distinctMaterialTextures.Count > 1)
- {
- if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Texture " + matTex.GetTexName() + "is tiled by " + matTex.matTilingRect.size + " tiling will be baked into a texture with maxSize:" + data._maxTilingBakeSize);
- }
- if (!txs.obUVscale.Equals(Vector2.one) && data.distinctMaterialTextures.Count > 1 && data._fixOutOfBoundsUVs)
- {
- if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Texture " + matTex.GetTexName() + " has out of bounds UVs that effectively tile by " + txs.obUVscale + " tiling will be baked into a texture with maxSize:" + data._maxTilingBakeSize);
- }
- if (matTex.isNull)
- {
- txs.SetEncapsulatingRect(propIdx, data._fixOutOfBoundsUVs);
- if (LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log(String.Format("No source texture creating a 16x16 texture for {0} texSet {1} srcMat {2}", data.texPropertyNames[propIdx].name, i, txs.matsAndGOs.mats[0].GetMaterialName()));
- }
- if (!matTex.isNull)
- {
- Vector2 dim = MB3_TextureCombinerPipeline.GetAdjustedForScaleAndOffset2Dimensions(matTex, txs.obUVoffset, txs.obUVscale, data, LOG_LEVEL);
- if ((int)(dim.x * dim.y) > tWidth * tHeight)
- {
- if (LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log(" matTex " + matTex.GetTexName() + " " + dim + " has a bigger size than " + tWidth + " " + tHeight);
- tWidth = (int)dim.x;
- tHeight = (int)dim.y;
- }
- }
- }
- }
- if (data._resizePowerOfTwoTextures)
- {
- if (tWidth <= _padding * 5)
- {
- Debug.LogWarning(String.Format("Some of the textures have widths close to the size of the padding. It is not recommended to use _resizePowerOfTwoTextures with widths this small.", txs.ToString()));
- }
- if (tHeight <= _padding * 5)
- {
- Debug.LogWarning(String.Format("Some of the textures have heights close to the size of the padding. It is not recommended to use _resizePowerOfTwoTextures with heights this small.", txs.ToString()));
- }
- if (IsPowerOfTwo(tWidth))
- {
- tWidth -= _padding * 2;
- }
- if (IsPowerOfTwo(tHeight))
- {
- tHeight -= _padding * 2;
- }
- if (tWidth < 1) tWidth = 1;
- if (tHeight < 1) tHeight = 1;
- }
- if (LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log(" Ideal size is " + tWidth + " " + tHeight);
- txs.idealWidth = tWidth;
- txs.idealHeight = tHeight;
- }
- data._atlasPadding = _padding;
- if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Total time Step2 Calculate Ideal Sizes part1: " + sw.Elapsed.ToString());
- yield break;
- }
- internal virtual AtlasPackingResult[] RunTexturePackerOnly(TexturePipelineData data, bool doSplitIntoMultiAtlasIfTooBig, MB_AtlasesAndRects resultAtlasesAndRects, MB_ITextureCombinerPacker texturePacker, MB2_LogLevel LOG_LEVEL)
- {
- AtlasPackingResult[] apr = texturePacker.CalculateAtlasRectangles(data, doSplitIntoMultiAtlasIfTooBig, LOG_LEVEL); // __RuntTexturePackerOnly(data, texturePacker, LOG_LEVEL);
- FillAtlasPackingResultAuxillaryData(data, apr);
- Texture2D[] atlases = new Texture2D[data.texPropertyNames.Count];
- if (!doSplitIntoMultiAtlasIfTooBig)
- {
- FillResultAtlasesAndRects(data, apr[0], resultAtlasesAndRects, atlases);
- }
- return apr;
- }
- internal virtual MB_ITextureCombinerPacker CreatePacker(bool onlyOneTextureInAtlasReuseTextures, MB2_PackingAlgorithmEnum packingAlgorithm)
- {
- if (onlyOneTextureInAtlasReuseTextures)
- {
- return new MB3_TextureCombinerPackerOneTextureInAtlas();
- }
- else if (packingAlgorithm == MB2_PackingAlgorithmEnum.UnitysPackTextures)
- {
- return new MB3_TextureCombinerPackerUnity();
- }
- else if (packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal)
- {
- if (USE_EXPERIMENTAL_HOIZONTALVERTICAL)
- {
- return new MB3_TextureCombinerPackerMeshBakerHorizontalVertical(MB3_TextureCombinerPackerMeshBakerHorizontalVertical.AtlasDirection.horizontal);
- } else
- {
- return new MB3_TextureCombinerPackerMeshBaker();
- }
-
- }
- else if (packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical)
- {
- if (USE_EXPERIMENTAL_HOIZONTALVERTICAL)
- {
- return new MB3_TextureCombinerPackerMeshBakerHorizontalVertical(MB3_TextureCombinerPackerMeshBakerHorizontalVertical.AtlasDirection.vertical);
- } else
- {
- return new MB3_TextureCombinerPackerMeshBaker();
- }
- }
- else if (packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker)
- {
- return new MB3_TextureCombinerPackerMeshBaker();
- }
- else
- {
- return new MB3_TextureCombinerPackerMeshBakerFast();
- }
- }
- internal virtual IEnumerator __Step3_BuildAndSaveAtlasesAndStoreResults(MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult result,
- ProgressUpdateDelegate progressInfo,
- TexturePipelineData data,
- MB3_TextureCombiner combiner,
- MB_ITextureCombinerPacker packer,
- AtlasPackingResult atlasPackingResult,
- MB2_EditorMethodsInterface textureEditorMethods, MB_AtlasesAndRects resultAtlasesAndRects,
- StringBuilder report,
- MB2_LogLevel LOG_LEVEL)
- {
- System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
- sw.Start();
- //run the garbage collector to free up as much memory as possible before bake to reduce MissingReferenceException problems
- GC.Collect();
- Texture2D[] atlases = new Texture2D[data.numAtlases];
- if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("time Step 3 Create And Save Atlases part 1 " + sw.Elapsed.ToString());
- yield return packer.CreateAtlases(progressInfo, data, combiner, atlasPackingResult, atlases, textureEditorMethods, LOG_LEVEL);
- float t3 = sw.ElapsedMilliseconds;
- data.nonTexturePropertyBlender.AdjustNonTextureProperties(data.resultMaterial, data.texPropertyNames, textureEditorMethods);
- if (data.distinctMaterialTextures.Count > 0) data.distinctMaterialTextures[0].AdjustResultMaterialNonTextureProperties(data.resultMaterial, data.texPropertyNames);
- if (progressInfo != null) progressInfo("Building Report", .7f);
- //report on atlases created
- StringBuilder atlasMessage = new StringBuilder();
- atlasMessage.AppendLine("---- Atlases ------");
- for (int i = 0; i < data.numAtlases; i++)
- {
- if (atlases[i] != null)
- {
- atlasMessage.AppendLine("Created Atlas For: " + data.texPropertyNames[i].name + " h=" + atlases[i].height + " w=" + atlases[i].width);
- }
- else if (!_ShouldWeCreateAtlasForThisProperty(i, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
- {
- atlasMessage.AppendLine("Did not create atlas for " + data.texPropertyNames[i].name + " because all source textures were null.");
- }
- }
- report.Append(atlasMessage.ToString());
- FillResultAtlasesAndRects(data, atlasPackingResult, resultAtlasesAndRects, atlases);
- if (progressInfo != null) progressInfo("Restoring Texture Formats & Read Flags", .8f);
- combiner._destroyAllTemporaryTextures();
- if (textureEditorMethods != null) textureEditorMethods.RestoreReadFlagsAndFormats(progressInfo);
- if (report != null && LOG_LEVEL >= MB2_LogLevel.info) Debug.Log(report.ToString());
- if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Time Step 3 Create And Save Atlases part 3 " + (sw.ElapsedMilliseconds - t3).ToString("f5"));
- if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Total time Step 3 Create And Save Atlases " + sw.Elapsed.ToString());
- yield break;
- }
- private void FillAtlasPackingResultAuxillaryData(TexturePipelineData data, AtlasPackingResult[] atlasPackingResults)
- {
- for (int packingResultIdx = 0; packingResultIdx < atlasPackingResults.Length; packingResultIdx++)
- {
- List<MatsAndGOs> matsList = new List<MatsAndGOs>();
- AtlasPackingResult packingResult = atlasPackingResults[packingResultIdx];
- List<MB_MaterialAndUVRect> auxData = new List<MB_MaterialAndUVRect>();
- for (int aprTexIdx = 0; aprTexIdx < packingResult.srcImgIdxs.Length; aprTexIdx++)
- {
- int srcTexIdx = packingResult.srcImgIdxs[aprTexIdx];
- MB_TexSet srcTexSet = data.distinctMaterialTextures[srcTexIdx];
- List<MatAndTransformToMerged> mergedMats = srcTexSet.matsAndGOs.mats;
- Rect allPropsUseSameTiling_encapsulatingSamplingRect, propsUseDifferntTiling_obUVRect;
- srcTexSet.GetRectsForTextureBakeResults(out allPropsUseSameTiling_encapsulatingSamplingRect, out propsUseDifferntTiling_obUVRect);
- // A single rectangle in the atlas can be shared by multiple source materials
- for (int matIdx = 0; matIdx < mergedMats.Count; matIdx++)
- {
- Rect allPropsUseSameTiling_sourceMaterialTiling = srcTexSet.GetMaterialTilingRectForTextureBakerResults(matIdx);
- MB_MaterialAndUVRect srcMatData = new MB_MaterialAndUVRect(
- mergedMats[matIdx].mat,
- packingResult.rects[aprTexIdx],
- srcTexSet.allTexturesUseSameMatTiling,
- allPropsUseSameTiling_sourceMaterialTiling,
- allPropsUseSameTiling_encapsulatingSamplingRect,
- propsUseDifferntTiling_obUVRect,
- srcTexSet.tilingTreatment,
- mergedMats[matIdx].objName);
- srcMatData.objectsThatUse = new List<GameObject>(srcTexSet.matsAndGOs.gos);
- auxData.Add(srcMatData);
- }
- }
- packingResult.data = auxData;
- }
- }
- private void FillResultAtlasesAndRects(TexturePipelineData data, AtlasPackingResult atlasPackingResult, MB_AtlasesAndRects resultAtlasesAndRects, Texture2D[] atlases)
- {
- List<MB_MaterialAndUVRect> mat2rect_map = new List<MB_MaterialAndUVRect>();
- Debug.Assert(atlasPackingResult.rects.Length == data.distinctMaterialTextures.Count, "Number of rects should equal the number of distinct matarial textures." + atlasPackingResult.rects.Length + " " + data.distinctMaterialTextures.Count);
- for (int rectInAtlasIdx = 0; rectInAtlasIdx < data.distinctMaterialTextures.Count; rectInAtlasIdx++)
- {
- MB_TexSet texSet = data.distinctMaterialTextures[rectInAtlasIdx];
- List<MatAndTransformToMerged> mergedMats = texSet.matsAndGOs.mats;
- Rect allPropsUseSameTiling_encapsulatingSamplingRect, propsUseDifferntTiling_obUVRect;
- texSet.GetRectsForTextureBakeResults(out allPropsUseSameTiling_encapsulatingSamplingRect, out propsUseDifferntTiling_obUVRect);
- // A single rectangle in the atlas can be shared by multiple source materials
- for (int matIdx = 0; matIdx < mergedMats.Count; matIdx++)
- {
- Rect allPropsUseSameTiling_sourceMaterialTiling = texSet.GetMaterialTilingRectForTextureBakerResults(matIdx);
- MB_MaterialAndUVRect key = new MB_MaterialAndUVRect(
- mergedMats[matIdx].mat,
- atlasPackingResult.rects[rectInAtlasIdx],
- texSet.allTexturesUseSameMatTiling,
- allPropsUseSameTiling_sourceMaterialTiling,
- allPropsUseSameTiling_encapsulatingSamplingRect,
- propsUseDifferntTiling_obUVRect,
- texSet.tilingTreatment,
- mergedMats[matIdx].objName);
- if (!mat2rect_map.Contains(key))
- {
- mat2rect_map.Add(key);
- }
- }
- }
- resultAtlasesAndRects.atlases = atlases; // one per texture on result shader
- resultAtlasesAndRects.texPropertyNames = ShaderTextureProperty.GetNames(data.texPropertyNames); // one per texture on source shader
- resultAtlasesAndRects.mat2rect_map = mat2rect_map;
- }
- internal virtual StringBuilder GenerateReport(MB3_TextureCombinerPipeline.TexturePipelineData data)
- {
- //generate report want to do this before
- StringBuilder report = new StringBuilder();
- if (data.numAtlases > 0)
- {
- report = new StringBuilder();
- report.AppendLine("Report");
- for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
- {
- MB_TexSet txs = data.distinctMaterialTextures[i];
- report.AppendLine("----------");
- report.Append("This set of textures will be resized to:" + txs.idealWidth + "x" + txs.idealHeight + "\n");
- for (int j = 0; j < txs.ts.Length; j++)
- {
- if (!txs.ts[j].isNull)
- {
- report.Append(" [" + data.texPropertyNames[j].name + " " + txs.ts[j].GetTexName() + " " + txs.ts[j].width + "x" + txs.ts[j].height + "]");
- if (txs.ts[j].matTilingRect.size != Vector2.one || txs.ts[j].matTilingRect.min != Vector2.zero) report.AppendFormat(" material scale {0} offset{1} ", txs.ts[j].matTilingRect.size.ToString("G4"), txs.ts[j].matTilingRect.min.ToString("G4"));
- if (txs.obUVscale != Vector2.one || txs.obUVoffset != Vector2.zero) report.AppendFormat(" obUV scale {0} offset{1} ", txs.obUVscale.ToString("G4"), txs.obUVoffset.ToString("G4"));
- report.AppendLine("");
- }
- else
- {
- report.Append(" [" + data.texPropertyNames[j].name + " null ");
- if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(j, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
- {
- report.Append("no atlas will be created all textures null]\n");
- }
- else
- {
- report.AppendFormat("a 16x16 texture will be created]\n");
- }
- }
- }
- report.AppendLine("");
- report.Append("Materials using:");
- for (int j = 0; j < txs.matsAndGOs.mats.Count; j++)
- {
- report.Append(txs.matsAndGOs.mats[j].mat.name + ", ");
- }
- report.AppendLine("");
- }
- }
- return report;
- }
- /*
- internal static AtlasPackingResult[] __RuntTexturePackerOnly(TexturePipelineData data, MB_ITextureCombinerPacker texturePacker, MB2_LogLevel LOG_LEVEL)
- {
- AtlasPackingResult[] packerRects;
- if (data.OnlyOneTextureInAtlasReuseTextures())
- {
- if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture");
- packerRects = new AtlasPackingResult[1];
- AtlasPadding[] paddings = new AtlasPadding[] { new AtlasPadding(data._atlasPadding) };
- packerRects[0] = new AtlasPackingResult(paddings);
- packerRects[0].rects = new Rect[1];
- packerRects[0].srcImgIdxs = new int[] { 0 };
- packerRects[0].rects[0] = new Rect(0f, 0f, 1f, 1f);
- MeshBakerMaterialTexture dmt = null;
- if (data.distinctMaterialTextures[0].ts.Length > 0)
- {
- dmt = data.distinctMaterialTextures[0].ts[0];
- }
- packerRects[0].atlasX = dmt.isNull ? 16 : dmt.width;
- packerRects[0].atlasY = dmt.isNull ? 16 : dmt.height;
- packerRects[0].usedW = dmt.isNull ? 16 : dmt.width;
- packerRects[0].usedH = dmt.isNull ? 16 : dmt.height;
- }
- else
- {
- List<Vector2> imageSizes = new List<Vector2>();
- List<AtlasPadding> paddings = new List<AtlasPadding>();
- for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
- {
- imageSizes.Add(new Vector2(data.distinctMaterialTextures[i].idealWidth, data.distinctMaterialTextures[i].idealHeight));
- paddings.Add(new AtlasPadding(data._atlasPadding));
- }
- MB2_TexturePacker tp = CreateTexturePacker(data._packingAlgorithm);
- tp.atlasMustBePowerOfTwo = data._meshBakerTexturePackerForcePowerOfTwo;
- packerRects = tp.GetRects(imageSizes, paddings, data._maxAtlasSize, data._maxAtlasSize, true);
- //Debug.Assert(packerRects.Length != 0);
- }
- return packerRects;
- }
- */
- internal static MB2_TexturePacker CreateTexturePacker(MB2_PackingAlgorithmEnum _packingAlgorithm)
- {
- if (_packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker)
- {
- return new MB2_TexturePackerRegular();
- }
- else if (_packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Fast)
- {
- return new MB2_TexturePackerRegular();
- }
- else if (_packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal)
- {
- MB2_TexturePackerHorizontalVert tp = new MB2_TexturePackerHorizontalVert();
- tp.packingOrientation = MB2_TexturePackerHorizontalVert.TexturePackingOrientation.horizontal;
- return tp;
- }
- else if (_packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical)
- {
- MB2_TexturePackerHorizontalVert tp = new MB2_TexturePackerHorizontalVert();
- tp.packingOrientation = MB2_TexturePackerHorizontalVert.TexturePackingOrientation.vertical;
- return tp;
- }
- else
- {
- Debug.LogError("packing algorithm must be one of the MeshBaker options to create a Texture Packer");
- }
- return null;
- }
- internal static Vector2 GetAdjustedForScaleAndOffset2Dimensions(MeshBakerMaterialTexture source, Vector2 obUVoffset, Vector2 obUVscale, TexturePipelineData data, MB2_LogLevel LOG_LEVEL)
- {
- if (source.matTilingRect.x == 0f && source.matTilingRect.y == 0f && source.matTilingRect.width == 1f && source.matTilingRect.height == 1f)
- {
- if (data._fixOutOfBoundsUVs)
- {
- if (obUVoffset.x == 0f && obUVoffset.y == 0f && obUVscale.x == 1f && obUVscale.y == 1f)
- {
- return new Vector2(source.width, source.height); //no adjustment necessary
- }
- }
- else
- {
- return new Vector2(source.width, source.height); //no adjustment necessary
- }
- }
- if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("GetAdjustedForScaleAndOffset2Dimensions: " + source.GetTexName() + " " + obUVoffset + " " + obUVscale);
- Rect encapsulatingSamplingRect = source.GetEncapsulatingSamplingRect().GetRect();
- float newWidth = encapsulatingSamplingRect.width * source.width;
- float newHeight = encapsulatingSamplingRect.height * source.height;
- if (newWidth > data._maxTilingBakeSize) newWidth = data._maxTilingBakeSize;
- if (newHeight > data._maxTilingBakeSize) newHeight = data._maxTilingBakeSize;
- if (newWidth < 1f) newWidth = 1f;
- if (newHeight < 1f) newHeight = 1f;
- return new Vector2(newWidth, newHeight);
- }
- /*
- Unity uses a non-standard format for storing normals for some platforms. Imagine the standard format is English, Unity's is French
- When the normal-map checkbox is ticked on the asset importer the normal map is translated into french. When we build the normal atlas
- we are reading the french. When we save and click the normal map tickbox we are translating french -> french. A double transladion that
- breaks the normal map. To fix this we need to "unconvert" the normal map to english when saving the atlas as a texture so that unity importer
- can do its thing properly.
- */
- internal static Color32 ConvertNormalFormatFromUnity_ToStandard(Color32 c)
- {
- Vector3 n = Vector3.zero;
- n.x = c.a * 2f - 1f;
- n.y = c.g * 2f - 1f;
- n.z = Mathf.Sqrt(1 - n.x * n.x - n.y * n.y);
- //now repack in the regular format
- Color32 cc = new Color32();
- cc.a = 1;
- cc.r = (byte)((n.x + 1f) * .5f);
- cc.g = (byte)((n.y + 1f) * .5f);
- cc.b = (byte)((n.z + 1f) * .5f);
- return cc;
- }
- /// <summary>
- /// Returns the tiling scale and offset for a given material.
- ///
- /// The only reason that this method is necessary is the Standard shader. Each texture in a material has a scale and offset stored with it.
- /// Most shaders use the scale and offset accociated with each texture map. The Standard shader does not do this. It uses the scale and offset
- /// associated with _MainTex for most of the maps.
- /// </summary>
- internal static void GetMaterialScaleAndOffset(Material mat, string propertyName, out Vector2 offset, out Vector2 scale)
- {
- if (mat == null)
- {
- Debug.LogError("Material was null. Should never happen.");
- offset = Vector2.zero;
- scale = Vector2.one;
- }
- if ((mat.shader.name.Equals("Standard") || mat.shader.name.Equals("Standard (Specular setup)")) && mat.HasProperty("_MainTex"))
- {
- offset = mat.GetTextureOffset("_MainTex");
- scale = mat.GetTextureScale("_MainTex");
- } else
- {
- offset = mat.GetTextureOffset(propertyName);
- scale = mat.GetTextureScale(propertyName);
- }
- }
- internal static float GetSubmeshArea(Mesh m, int submeshIdx)
- {
- if (submeshIdx >= m.subMeshCount || submeshIdx < 0)
- {
- return 0f;
- }
- Vector3[] vs = m.vertices;
- int[] tris = m.GetIndices(submeshIdx);
- float area = 0f;
- for (int i = 0; i < tris.Length; i += 3)
- {
- Vector3 v0 = vs[tris[i]];
- Vector3 v1 = vs[tris[i + 1]];
- Vector3 v2 = vs[tris[i + 2]];
- Vector3 cross = Vector3.Cross(v1 - v0, v2 - v0);
- area += cross.magnitude / 2f;
- }
- return area;
- }
- internal static bool IsPowerOfTwo(int x)
- {
- return (x & (x - 1)) == 0;
- }
- }
- }
|