//进行完整性检查合并 public void DoIntegrityCheckMergedEncapsulatingSamplingRects(List <MaterialPropTexturesSet> distinctMaterialTextures) { if (MeshBakerRoot.DO_INTEGRITY_CHECKS) { for (int i = 0; i < distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet tx1 = distinctMaterialTextures[i]; if (!tx1.allTexturesUseSameMatTiling) { continue; } for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { MatAndTransformToMerged mat = tx1.matsAndGOs.mats[matIdx]; DRect uvR = mat.obUVRectIfTilingSame; DRect matR = mat.materialTiling; //if (!MB2_TextureBakeResults.IsMeshAndMaterialRectEnclosedByAtlasRect(tx1.tilingTreatment, // uvR.GetRect(), matR.GetRect(), tx1.ts[0].GetEncapsulatingSamplingRect().GetRect(),MB2_LogLevel.info)) //{ // Debug.LogErrorFormat("mesh " + tx1.matsAndGOs.mats[matIdx].objName + "\n" + // " uv=" + uvR + "\n" + // " mat=" + matR.GetRect().ToString("f5") + "\n" + // " samplingRect=" + tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling.GetRect().ToString("f4") + "\n" + // " encapsulatingRect " + tx1.ts[0].GetEncapsulatingSamplingRect().GetRect().ToString("f4") + "\n"); // Debug.LogErrorFormat(string.Format("Integrity check failed. " + tx1.matsAndGOs.mats[matIdx].objName + " Encapsulating sampling rect failed to contain potentialRect\n")); // MB2_TextureBakeResults.IsMeshAndMaterialRectEnclosedByAtlasRect(tx1.tilingTreatment, uvR.GetRect(), matR.GetRect(), tx1.ts[0].GetEncapsulatingSamplingRect().GetRect(), MB2_LogLevel.trace); // Debug.Assert(false); //} //} } } } }
public void SortTexSetIntoBins(MaterialPropTexturesSet texSet, List <MaterialPropTexturesSet> horizontalVert, List <MaterialPropTexturesSet> regular, int maxAtlasWidth, int maxAtlasHeight) { if (texSet.idealHeight >= maxAtlasHeight && texSet.ts[0].GetEncapsulatingSamplingRect().height >= 1f) { horizontalVert.Add(texSet); } else { regular.Add(texSet); } }
internal static StringBuilder GenerateReport(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++) { MaterialPropTexturesSet 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 (!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 void CreateTemporaryTexturesForAtlas(List <MaterialPropTexturesSet> distinctMaterialTextures, TextureCombineHandler combiner, int propIdx, TexturePipelineData data) { for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++) { MaterialPropTexturesSet txs = data.distinctMaterialTextures[texSetIdx]; MaterialPropTexture matTex = txs.ts[propIdx]; if (matTex.isNull) { //create a small 16 x 16 texture to use in the atlas Color col = data.nonTexturePropertyBlender.GetColorForTemporaryTexture(txs.matsAndGOs.mats[0].mat, data.texPropertyNames[propIdx]); txs.CreateColoredTexToReplaceNull(data.texPropertyNames[propIdx].name, propIdx, data._fixOutOfBoundsUVs, combiner, col); } } }
public Texture2D TintTextureWithTextureCombiner(Texture2D t, MaterialPropTexturesSet sourceMaterial, ShaderTextureProperty shaderPropertyName) { Debug.Assert(resultMaterialTextureBlender != null); resultMaterialTextureBlender.OnBeforeTintTexture(sourceMaterial.matsAndGOs.mats[0].mat, shaderPropertyName.name); Debug.Log(string.Format("Blending texture {0} mat {1} with non-texture properties using TextureBlender {2}", t.name, sourceMaterial.matsAndGOs.mats[0].mat, resultMaterialTextureBlender)); for (int i = 0; i < t.height; i++) { Color[] cs = t.GetPixels(0, i, t.width, 1); for (int j = 0; j < cs.Length; j++) { cs[j] = resultMaterialTextureBlender.OnBlendTexturePixel(shaderPropertyName.name, cs[j]); } t.SetPixels(0, i, t.width, 1, cs); } t.Apply(); return(t); }
// The two texture sets are equal if they are using the same // textures/color properties for each map and have the same // tiling for each of those color properties internal bool IsEqual(object obj, bool fixOutOfBoundsUVs, TextureCombinerNonTextureProperties resultMaterialTextureBlender) { if (!(obj is MaterialPropTexturesSet)) { return(false); } MaterialPropTexturesSet other = (MaterialPropTexturesSet)obj; if (other.ts.Length != ts.Length) { return(false); } else { for (int i = 0; i < ts.Length; i++) { if (ts[i].matTilingRect != other.ts[i].matTilingRect) { return(false); } if (!ts[i].AreTexturesEqual(other.ts[i])) { return(false); } if (!resultMaterialTextureBlender.NonTexturePropertiesAreEqual(matsAndGOs.mats[0].mat, other.matsAndGOs.mats[0].mat)) { return(false); } } //IMPORTANT don't use Vector2 != Vector2 because it is only acurate to about 5 decimal places //this can lead to tiled rectangles that can't accept rectangles. if (fixOutOfBoundsUVs && (obUVoffset.x != other.obUVoffset.x || obUVoffset.y != other.obUVoffset.y)) { return(false); } if (fixOutOfBoundsUVs && (obUVscale.x != other.obUVscale.x || obUVscale.y != other.obUVscale.y)) { return(false); } return(true); } }
public bool AllTexturesAreSameForMerge(MaterialPropTexturesSet other, bool considerNonTextureProperties, TextureCombinerNonTextureProperties resultMaterialTextureBlender) { if (other.ts.Length != ts.Length) { return(false); } else { if (!other.allTexturesUseSameMatTiling || !allTexturesUseSameMatTiling) { return(false); } // must use same set of textures int idxOfFirstNoneNull = -1; for (int i = 0; i < ts.Length; i++) { if (!ts[i].AreTexturesEqual(other.ts[i])) { return(false); } if (idxOfFirstNoneNull == -1 && !ts[i].isNull) { idxOfFirstNoneNull = i; } if (considerNonTextureProperties) { if (!resultMaterialTextureBlender.NonTexturePropertiesAreEqual(matsAndGOs.mats[0].mat, other.matsAndGOs.mats[0].mat)) { return(false); } } } if (idxOfFirstNoneNull != -1) { //check that all textures are the same. Have already checked all tiling is same for (int i = 0; i < ts.Length; i++) { if (!ts[i].AreTexturesEqual(other.ts[i])) { return(false); } } } return(true); } }
internal static AtlasPackingResult[] RunTexturePackerOnly(TexturePipelineData data, bool doSplitIntoMultiAtlasIfTooBig, ITextureCombinerPacker texturePacker) { AtlasPackingResult[] apr = texturePacker.CalculateAtlasRectangles(data, doSplitIntoMultiAtlasIfTooBig); //copy materials PackingResults for (int i = 0; i < apr.Length; i++) { List <MatsAndGOs> matsList = new List <MatsAndGOs>(); apr[i].data = matsList; for (int j = 0; j < apr[i].srcImgIdxs.Length; j++) { MaterialPropTexturesSet ts = data.distinctMaterialTextures[apr[i].srcImgIdxs[j]]; matsList.Add(ts.matsAndGOs); } } return(apr); }
public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, TexturePipelineData data, TextureCombineHandler combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, EditorMethodsInterface textureEditorMethods) { Rect[] uvRects = packedAtlasRects.rects; int atlasSizeX = packedAtlasRects.atlasX; int atlasSizeY = packedAtlasRects.atlasY; Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY); for (int propIdx = 0; propIdx < data.numAtlases; propIdx++) { Texture2D atlas = null; ShaderTextureProperty property = data.texPropertyNames[propIdx]; if (!TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { atlas = null; Debug.Log("=== Not creating atlas for " + property.name + " because textures are null and default value parameters are the same."); } else { Debug.Log("=== Creating atlas for " + property.name); GC.Collect(); CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data); //use a jagged array because it is much more efficient in memory Color[][] atlasPixels = new Color[atlasSizeY][]; for (int j = 0; j < atlasPixels.Length; j++) { atlasPixels[j] = new Color[atlasSizeX]; } bool isNormalMap = false; if (property.isNormalMap) { isNormalMap = true; } for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++) { MaterialPropTexturesSet texSet = data.distinctMaterialTextures[texSetIdx]; MaterialPropTexture matTex = texSet.ts[propIdx]; string s = "Creating Atlas '" + property.name + "' texture " + matTex.GetTexName(); if (progressInfo != null) { progressInfo(s, .01f); } Debug.Log(string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName())); Rect r = uvRects[texSetIdx]; Texture2D t = texSet.ts[propIdx].GetTexture2D(); int x = Mathf.RoundToInt(r.x * atlasSizeX); int y = Mathf.RoundToInt(r.y * atlasSizeY); int ww = Mathf.RoundToInt(r.width * atlasSizeX); int hh = Mathf.RoundToInt(r.height * atlasSizeY); if (ww == 0 || hh == 0) { Debug.LogError("Image in atlas has no height or width " + r); } if (progressInfo != null) { progressInfo(s + " set ReadWrite flag", .01f); } if (textureEditorMethods != null) { textureEditorMethods.SetReadWriteFlag(t, true, true); } if (progressInfo != null) { progressInfo(s + "Copying to atlas: '" + matTex.GetTexName() + "'", .02f); } DRect samplingRect = texSet.ts[propIdx].GetEncapsulatingSamplingRect(); Debug.Assert(!texSet.ts[propIdx].isNull, string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName())); yield return(CopyScaledAndTiledToAtlas(texSet.ts[propIdx], texSet, property, samplingRect, x, y, ww, hh, packedAtlasRects.padding[texSetIdx], atlasPixels, isNormalMap, data, combiner, progressInfo)); } yield return(data.numAtlases); if (progressInfo != null) { progressInfo("Applying changes to atlas: '" + property.name + "'", .03f); } atlas = new Texture2D(atlasSizeX, atlasSizeY, TextureFormat.ARGB32, true); for (int j = 0; j < atlasPixels.Length; j++) { atlas.SetPixels(0, j, atlasSizeX, 1, atlasPixels[j]); } atlas.Apply(); Debug.Log("Saving atlas " + property.name + " w=" + atlas.width + " h=" + atlas.height); } atlases[propIdx] = atlas; if (progressInfo != null) { progressInfo("Saving atlas: '" + property.name + "'", .04f); } if (data._saveAtlasesAsAssets && textureEditorMethods != null) { textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], data.texPropertyNames[propIdx], propIdx, data.resultMaterial); } else { data.resultMaterial.SetTexture(data.texPropertyNames[propIdx].name, atlases[propIdx]); } data.resultMaterial.SetTextureOffset(data.texPropertyNames[propIdx].name, Vector2.zero); data.resultMaterial.SetTextureScale(data.texPropertyNames[propIdx].name, Vector2.one); combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name); } yield break; }
private void CopyScaledAndTiledToAtlas(MaterialPropTexturesSet texSet, MaterialPropTexture source, Vector2 obUVoffset, Vector2 obUVscale, Rect rec, ShaderTextureProperty texturePropertyName, TextureCombinerNonTextureProperties resultMatTexBlender, bool yIsFlipped) { Rect r = rec; myCamera.backgroundColor = resultMatTexBlender.GetColorForTemporaryTexture(texSet.matsAndGOs.mats[0].mat, texturePropertyName); //yIsFlipped = true; //if (yIsFlipped) //{ //} r.y = 1f - (r.y + r.height); // DrawTexture uses topLeft 0,0, Texture2D uses bottomLeft 0,0 r.x *= _destinationTexture.width; r.y *= _destinationTexture.height; r.width *= _destinationTexture.width; r.height *= _destinationTexture.height; Rect rPadded = r; rPadded.x -= _padding; rPadded.y -= _padding; rPadded.width += _padding * 2; rPadded.height += _padding * 2; Rect targPr = new Rect(); Rect srcPrTex = texSet.ts[indexOfTexSetToRender].GetEncapsulatingSamplingRect().GetRect(); if (!_fixOutOfBoundsUVs) { Debug.Assert(source.matTilingRect.GetRect() == texSet.ts[indexOfTexSetToRender].GetEncapsulatingSamplingRect().GetRect()); } Texture2D tex = source.GetTexture2D(); /* * if (_considerNonTextureProperties && resultMatTexBlender != null) * { * if (LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log(string.Format("Blending texture {0} mat {1} with non-texture properties using TextureBlender {2}", tex.name, texSet.mats[0].mat, resultMatTexBlender)); * * resultMatTexBlender.OnBeforeTintTexture(texSet.mats[0].mat, texturePropertyName.name); * //combine the tintColor with the texture * tex = combiner._createTextureCopy(tex); * for (int i = 0; i < tex.height; i++) * { * Color[] cs = tex.GetPixels(0, i, tex.width, 1); * for (int j = 0; j < cs.Length; j++) * { * cs[j] = resultMatTexBlender.OnBlendTexturePixel(texturePropertyName.name, cs[j]); * } * tex.SetPixels(0, i, tex.width, 1, cs); * } * tex.Apply(); * } */ //main texture TextureWrapMode oldTexWrapMode = tex.wrapMode; if (srcPrTex.width == 1f && srcPrTex.height == 1f && srcPrTex.x == 0f && srcPrTex.y == 0f) { //fixes bug where there is a dark line at the edge of the texture tex.wrapMode = TextureWrapMode.Clamp; } else { tex.wrapMode = TextureWrapMode.Repeat; } Debug.Log("DrawTexture tex=" + tex.name + " destRect=" + r + " srcRect=" + srcPrTex + " Mat=" + mat); //fill the padding first Rect srcPr = new Rect(); //top margin srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y + 1 - 1f / tex.height; srcPr.width = srcPrTex.width; srcPr.height = 1f / tex.height; targPr.x = r.x; targPr.y = rPadded.y; targPr.width = r.width; targPr.height = _padding; RenderTexture oldRT = RenderTexture.active; RenderTexture.active = _destinationTexture; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //bot margin srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y; srcPr.width = srcPrTex.width; srcPr.height = 1f / tex.height; targPr.x = r.x; targPr.y = r.y + r.height; targPr.width = r.width; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //left margin srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y; srcPr.width = 1f / tex.width; srcPr.height = srcPrTex.height; targPr.x = rPadded.x; targPr.y = r.y; targPr.width = _padding; targPr.height = r.height; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //right margin srcPr.x = srcPrTex.x + 1f - 1f / tex.width; srcPr.y = srcPrTex.y; srcPr.width = 1f / tex.width; srcPr.height = srcPrTex.height; targPr.x = r.x + r.width; targPr.y = r.y; targPr.width = _padding; targPr.height = r.height; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //top left corner srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y + 1 - 1f / tex.height; srcPr.width = 1f / tex.width; srcPr.height = 1f / tex.height; targPr.x = rPadded.x; targPr.y = rPadded.y; targPr.width = _padding; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //top right corner srcPr.x = srcPrTex.x + 1f - 1f / tex.width; srcPr.y = srcPrTex.y + 1 - 1f / tex.height; srcPr.width = 1f / tex.width; srcPr.height = 1f / tex.height; targPr.x = r.x + r.width; targPr.y = rPadded.y; targPr.width = _padding; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //bot left corner srcPr.x = srcPrTex.x; srcPr.y = srcPrTex.y; srcPr.width = 1f / tex.width; srcPr.height = 1f / tex.height; targPr.x = rPadded.x; targPr.y = r.y + r.height; targPr.width = _padding; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //bot right corner srcPr.x = srcPrTex.x + 1f - 1f / tex.width; srcPr.y = srcPrTex.y; srcPr.width = 1f / tex.width; srcPr.height = 1f / tex.height; targPr.x = r.x + r.width; targPr.y = r.y + r.height; targPr.width = _padding; targPr.height = _padding; Graphics.DrawTexture(targPr, tex, srcPr, 0, 0, 0, 0, mat); //now the texture Graphics.DrawTexture(r, tex, srcPrTex, 0, 0, 0, 0, mat); RenderTexture.active = oldRT; tex.wrapMode = oldTexWrapMode; }
internal static IEnumerator CopyScaledAndTiledToAtlas(MaterialPropTexture source, MaterialPropTexturesSet sourceMaterial, ShaderTextureProperty shaderPropertyName, DRect srcSamplingRect, int targX, int targY, int targW, int targH, AtlasPadding padding, Color[][] atlasPixels, bool isNormalMap, TexturePipelineData data, TextureCombineHandler combiner, ProgressUpdateDelegate progressInfo = null) { //HasFinished = false; Texture2D t = source.GetTexture2D(); Debug.Log(string.Format("CopyScaledAndTiledToAtlas: {0} inAtlasX={1} inAtlasY={2} inAtlasW={3} inAtlasH={4} paddX={5} paddY={6} srcSamplingRect={7}", t, targX, targY, targW, targH, padding.leftRight, padding.topBottom, srcSamplingRect)); float newWidth = targW; float newHeight = targH; float scx = (float)srcSamplingRect.width; float scy = (float)srcSamplingRect.height; float ox = (float)srcSamplingRect.x; float oy = (float)srcSamplingRect.y; int w = (int)newWidth; int h = (int)newHeight; if (data._considerNonTextureProperties) { t = combiner._createTextureCopy(shaderPropertyName.name, t); t = data.nonTexturePropertyBlender.TintTextureWithTextureCombiner(t, sourceMaterial, shaderPropertyName); } for (int i = 0; i < w; i++) { if (progressInfo != null && w > 0) { progressInfo("CopyScaledAndTiledToAtlas " + (((float)i / (float)w) * 100f).ToString("F0"), .2f); } for (int j = 0; j < h; j++) { float u = i / newWidth * scx + ox; float v = j / newHeight * scy + oy; atlasPixels[targY + j][targX + i] = t.GetPixelBilinear(u, v); } } //bleed the border colors into the padding for (int i = 0; i < w; i++) { for (int j = 1; j <= padding.topBottom; j++) { //top margin atlasPixels[(targY - j)][targX + i] = atlasPixels[(targY)][targX + i]; //bottom margin atlasPixels[(targY + h - 1 + j)][targX + i] = atlasPixels[(targY + h - 1)][targX + i]; } } for (int j = 0; j < h; j++) { for (int i = 1; i <= padding.leftRight; i++) { //left margin atlasPixels[(targY + j)][targX - i] = atlasPixels[(targY + j)][targX]; //right margin atlasPixels[(targY + j)][targX + w + i - 1] = atlasPixels[(targY + j)][targX + w - 1]; } } //corners for (int i = 1; i <= padding.leftRight; i++) { for (int j = 1; j <= padding.topBottom; j++) { atlasPixels[(targY - j)][targX - i] = atlasPixels[targY][targX]; atlasPixels[(targY + h - 1 + j)][targX - i] = atlasPixels[(targY + h - 1)][targX]; atlasPixels[(targY + h - 1 + j)][targX + w + i - 1] = atlasPixels[(targY + h - 1)][targX + w - 1]; atlasPixels[(targY - j)][targX + w + i - 1] = atlasPixels[targY][targX + w - 1]; yield return(null); } yield return(null); } yield break; }
public PipelineVariationSomeTexturesUseDifferentMatTiling(MaterialPropTexturesSet ts) { texSet = ts; Debug.Assert(texSet.allTexturesUseSameMatTiling == false); }
public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo, TexturePipelineData data, TextureCombineHandler combiner, AtlasPackingResult packedAtlasRects, Texture2D[] atlases, EditorMethodsInterface textureEditorMethods) { Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures()); Rect[] uvRects = packedAtlasRects.rects; long estArea = 0; int atlasSizeX = 1; int atlasSizeY = 1; uvRects = null; for (int propIdx = 0; propIdx < data.numAtlases; propIdx++) { //----------------------- ShaderTextureProperty prop = data.texPropertyNames[propIdx]; Texture2D atlas = null; if (!TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { atlas = null; } else { Debug.LogWarning("Beginning loop " + propIdx + " num temporary textures " + combiner._getNumTemporaryTextures()); TextureCombinerPackerBase.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data); Texture2D[] texToPack = new Texture2D[data.distinctMaterialTextures.Count]; for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++) { MaterialPropTexturesSet txs = data.distinctMaterialTextures[texSetIdx]; int tWidth = txs.idealWidth; int tHeight = txs.idealHeight; Texture2D tx = txs.ts[propIdx].GetTexture2D(); if (progressInfo != null) { progressInfo("Adjusting for scale and offset " + tx, .01f); } if (textureEditorMethods != null) { textureEditorMethods.SetReadWriteFlag(tx, true, true); } tx = GetAdjustedForScaleAndOffset2(prop.name, txs.ts[propIdx], txs.obUVoffset, txs.obUVscale, data, combiner); //create a resized copy if necessary if (tx.width != tWidth || tx.height != tHeight) { if (progressInfo != null) { progressInfo("Resizing texture '" + tx + "'", .01f); } Debug.LogWarning("Copying and resizing texture " + prop.name + " from " + tx.width + "x" + tx.height + " to " + tWidth + "x" + tHeight); tx = combiner._resizeTexture(prop.name, (Texture2D)tx, tWidth, tHeight); } estArea += tx.width * tx.height; if (data._considerNonTextureProperties) { //combine the tintColor with the texture tx = combiner._createTextureCopy(prop.name, tx); data.nonTexturePropertyBlender.TintTextureWithTextureCombiner(tx, data.distinctMaterialTextures[texSetIdx], prop); } texToPack[texSetIdx] = tx; } if (textureEditorMethods != null) { textureEditorMethods.CheckBuildSettings(estArea); } if (Math.Sqrt(estArea) > 3500f) { Debug.LogWarning("The maximum possible atlas size is 4096. Textures may be shrunk"); } atlas = new Texture2D(1, 1, TextureFormat.ARGB32, true); if (progressInfo != null) { progressInfo("Packing texture atlas " + prop.name, .25f); } if (propIdx == 0) { if (progressInfo != null) { progressInfo("Estimated min size of atlases: " + Math.Sqrt(estArea).ToString("F0"), .1f); } Debug.Log("Estimated atlas minimum size:" + Math.Sqrt(estArea).ToString("F0")); int maxAtlasSize = 4096; uvRects = atlas.PackTextures(texToPack, data._atlasPadding, maxAtlasSize, false); Debug.Log("After pack textures atlas size " + atlas.width + " " + atlas.height); atlasSizeX = atlas.width; atlasSizeY = atlas.height; atlas.Apply(); } else { if (progressInfo != null) { progressInfo("Copying Textures Into: " + prop.name, .1f); } atlas = _copyTexturesIntoAtlas(texToPack, data._atlasPadding, uvRects, atlasSizeX, atlasSizeY, combiner); } } atlases[propIdx] = atlas; //---------------------- if (data._saveAtlasesAsAssets && textureEditorMethods != null) { textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], prop, propIdx, data.resultMaterial); } data.resultMaterial.SetTextureOffset(prop.name, Vector2.zero); data.resultMaterial.SetTextureScale(prop.name, Vector2.one); combiner._destroyTemporaryTextures(prop.name); GC.Collect(); } packedAtlasRects.rects = uvRects; yield break; }
public override AtlasPackingResult[] CalculateAtlasRectangles(TexturePipelineData data, bool doMultiAtlas) { Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures()); Debug.Assert(data._packingAlgorithm != PackingAlgorithmEnum.UnitysPackTextures, "Unity texture packer cannot be used"); IPipeline pipeline; if (_atlasDirection == AtlasDirection.horizontal) { pipeline = new HorizontalPipeline(); } else { pipeline = new VerticalPipeline(); } //int maxAtlasWidth = data._maxAtlasWidth; //int maxAtlasHeight = data._maxAtlasHeight; if (_atlasDirection == AtlasDirection.horizontal) { if (!data._useMaxAtlasWidthOverride) { // need to get the width of the atlas without mesh uvs considered int maxWidth = 2; for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet ts = data.distinctMaterialTextures[i]; int w; if (data._fixOutOfBoundsUVs) { Vector2 rawHeightWidth = ts.GetMaxRawTextureHeightWidth(); w = (int)rawHeightWidth.x; } else { w = ts.idealWidth; } if (ts.idealWidth > maxWidth) { maxWidth = w; } } Debug.Log("Calculated max atlas width: " + maxWidth); data._maxAtlasWidth = maxWidth; } } else { if (!data._useMaxAtlasHeightOverride) { int maxHeight = 2; for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet ts = data.distinctMaterialTextures[i]; int h; if (data._fixOutOfBoundsUVs) { Vector2 rawHeightWidth = ts.GetMaxRawTextureHeightWidth(); h = (int)rawHeightWidth.y; } else { h = ts.idealHeight; } if (ts.idealHeight > maxHeight) { maxHeight = h; } } Debug.Log("Calculated max atlas height: " + maxHeight); data._maxAtlasHeight = maxHeight; } } //split the list of distinctMaterialTextures into two bins List <MaterialPropTexturesSet> horizontalVerticalDistinctMaterialTextures = new List <MaterialPropTexturesSet>(); List <MaterialPropTexturesSet> regularTextures = new List <MaterialPropTexturesSet>(); for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { pipeline.SortTexSetIntoBins(data.distinctMaterialTextures[i], horizontalVerticalDistinctMaterialTextures, regularTextures, data._maxAtlasWidth, data._maxAtlasHeight); } Debug.Log(String.Format("Splitting list of distinctMaterialTextures numHorizontalVertical={0} numRegular={1} maxAtlasWidth={2} maxAtlasHeight={3}", horizontalVerticalDistinctMaterialTextures.Count, regularTextures.Count, data._maxAtlasWidth, data._maxAtlasHeight)); //pack one bin with the horizontal vertical texture packer. TexturePacker tp; PackingAlgorithmEnum packingAlgorithm; AtlasPackingResult[] packerRectsHorizontalVertical; if (horizontalVerticalDistinctMaterialTextures.Count > 0) { packingAlgorithm = pipeline.GetPackingAlg(); List <Vector2> imageSizesHorizontalVertical = new List <Vector2>(); for (int i = 0; i < horizontalVerticalDistinctMaterialTextures.Count; i++) { horizontalVerticalDistinctMaterialTextures[i].SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(pipeline.GetEdge2EdgeTreatment()); imageSizesHorizontalVertical.Add(new Vector2(horizontalVerticalDistinctMaterialTextures[i].idealWidth, horizontalVerticalDistinctMaterialTextures[i].idealHeight)); } tp = CreateTexturePacker(packingAlgorithm); tp.atlasMustBePowerOfTwo = false; List <AtlasPadding> paddingsHorizontalVertical = new List <AtlasPadding>(); for (int i = 0; i < imageSizesHorizontalVertical.Count; i++) { AtlasPadding padding = new AtlasPadding(); pipeline.InitializeAtlasPadding(ref padding, data._atlasPadding); paddingsHorizontalVertical.Add(padding); } packerRectsHorizontalVertical = tp.GetRects(imageSizesHorizontalVertical, paddingsHorizontalVertical, data._maxAtlasWidth, data._maxAtlasHeight, false); Debug.Log(String.Format("Packed {0} textures with edgeToEdge tiling into an atlas of size {1} by {2} usedW {3} usedH {4}", horizontalVerticalDistinctMaterialTextures.Count, packerRectsHorizontalVertical[0].atlasX, packerRectsHorizontalVertical[0].atlasY, packerRectsHorizontalVertical[0].usedW, packerRectsHorizontalVertical[0].usedH)); } else { packerRectsHorizontalVertical = new AtlasPackingResult[0]; } //pack other bin with regular texture packer AtlasPackingResult[] packerRectsRegular; if (regularTextures.Count > 0) { packingAlgorithm = PackingAlgorithmEnum.MeshBakerTexturePacker; List <Vector2> imageSizesRegular = new List <Vector2>(); for (int i = 0; i < regularTextures.Count; i++) { imageSizesRegular.Add(new Vector2(regularTextures[i].idealWidth, regularTextures[i].idealHeight)); } tp = CreateTexturePacker(PackingAlgorithmEnum.MeshBakerTexturePacker); tp.atlasMustBePowerOfTwo = false; List <AtlasPadding> paddingsRegular = new List <AtlasPadding>(); for (int i = 0; i < imageSizesRegular.Count; i++) { AtlasPadding padding = new AtlasPadding(); padding.topBottom = data._atlasPadding; padding.leftRight = data._atlasPadding; paddingsRegular.Add(padding); } int atlasRegularMaxWidth, atlasRegularMaxHeight; int usedHorizontalVertWidth = 0, usedHorizontalVertHeight = 0; if (packerRectsHorizontalVertical.Length > 0) { usedHorizontalVertHeight = packerRectsHorizontalVertical[0].atlasY; usedHorizontalVertWidth = packerRectsHorizontalVertical[0].atlasX; } pipeline.GetExtraRoomForRegularAtlas(usedHorizontalVertWidth, usedHorizontalVertHeight, data._maxAtlasWidth, data._maxAtlasHeight, out atlasRegularMaxWidth, out atlasRegularMaxHeight); packerRectsRegular = tp.GetRects(imageSizesRegular, paddingsRegular, atlasRegularMaxWidth, atlasRegularMaxHeight, false); Debug.Log(String.Format("Packed {0} textures without edgeToEdge tiling into an atlas of size {1} by {2} usedW {3} usedH {4}", regularTextures.Count, packerRectsRegular[0].atlasX, packerRectsRegular[0].atlasY, packerRectsRegular[0].usedW, packerRectsRegular[0].usedH)); } else { packerRectsRegular = new AtlasPackingResult[0]; } AtlasPackingResult result = null; if (packerRectsHorizontalVertical.Length == 0 && packerRectsRegular.Length == 0) { Debug.Assert(false, "Should never have reached this."); return(null); } else if (packerRectsHorizontalVertical.Length > 0 && packerRectsRegular.Length > 0) { result = MergeAtlasPackingResultStackBonA(packerRectsHorizontalVertical[0], packerRectsRegular[0], data._maxAtlasWidth, data._maxAtlasHeight, true, pipeline); } else if (packerRectsHorizontalVertical.Length > 0) { result = packerRectsHorizontalVertical[0]; } else if (packerRectsRegular.Length > 0) { result = packerRectsRegular[0]; } Debug.Assert(data.distinctMaterialTextures.Count == result.rects.Length); //We re-ordered the distinctMaterial textures so replace the list with the new reordered one horizontalVerticalDistinctMaterialTextures.AddRange(regularTextures); data.distinctMaterialTextures = horizontalVerticalDistinctMaterialTextures; AtlasPackingResult[] results; if (result != null) { results = new AtlasPackingResult[] { result } } ; else { results = new AtlasPackingResult[0]; } return(results); }
public PipelineVariationAllTexturesUseSameMatTiling(MaterialPropTexturesSet ts) { texSet = ts; Debug.Assert(texSet.allTexturesUseSameMatTiling == true); }
public void SetEncapsulatingSamplingRect(MaterialPropTexturesSet ts, DRect r) { encapsulatingSamplingRect = r; }
internal Texture2D TintTextureWithTextureCombiner(Texture2D t, MaterialPropTexturesSet sourceMaterial, ShaderTextureProperty shaderPropertyName) { return(_nonTexturePropertiesBlender.TintTextureWithTextureCombiner(t, sourceMaterial, shaderPropertyName)); }
public Texture2D TintTextureWithTextureCombiner(Texture2D t, MaterialPropTexturesSet sourceMaterial, ShaderTextureProperty shaderPropertyName) { Debug.Assert(_textureProperties._considerNonTextureProperties == false); Debug.LogError("TintTextureWithTextureCombiner should never be called if resultMaterialTextureBlender is null"); return(t); }
public void MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(List <MaterialPropTexturesSet> distinctMaterialTextures) { int numMerged = 0; // IMPORTANT: Note that the verts stored in the mesh are NOT Normalized UV Coords. They are normalized * [UVTrans]. To get normalized UV // coords we must multiply them by [invUVTrans]. Need to do this to the verts in the mesh before we do any transforms with them. // Also check that all textures use same tiling. This is a prerequisite for merging. // Mark MB3_TexSet that are mergable (allTexturesUseSameMatTiling) //存储在网格中的顶点不是归一化UV坐标。 它们已归一化 * [UVTrans]。 //获得归一化的 UV 坐标必须将其乘以[invUVTrans]。 //在对它们进行任何转换之前,需要对网格中的顶点执行此操作。 //检查所有纹理是否使用相同的拼贴。 这是合并的先决条件。 //标记可合并的TexSet(allTexturesUseSameMatTiling) for (int i = 0; i < distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet matPropsTextureSet = distinctMaterialTextures[i]; int idxOfFirstNotNull = -1; bool allAreSame = true; DRect firstRect = new DRect(); //判断不是相同的 texture 资源 for (int propIdx = 0; propIdx < matPropsTextureSet.ts.Length; propIdx++) { if (idxOfFirstNotNull != -1) { if (!matPropsTextureSet.ts[propIdx].isNull && firstRect != matPropsTextureSet.ts[propIdx].matTilingRect) { allAreSame = false; } } //先找第一个非空纹理,设置为 idxOfFirstNotNull else if (!matPropsTextureSet.ts[propIdx].isNull) { idxOfFirstNotNull = propIdx; firstRect = matPropsTextureSet.ts[propIdx].matTilingRect; } } if (LOG_LEVEL_TRACE_MERGE_MAT_SUBRECTS == true) { if (allAreSame) { Debug.LogFormat("TextureSet {0} allTexturesUseSameMatTiling = {1}", i, allAreSame); } else { Debug.Log(string.Format("Textures in material(s) do not all use the same material tiling. " + "This set of textures will not be considered for merge: {0} ", matPropsTextureSet.GetDescription())); } } if (allAreSame) { matPropsTextureSet.SetAllTexturesUseSameMatTilingTrue(); } } //设置 材质Obj 名称 for (int i = 0; i < distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet matPropsTextureSet = distinctMaterialTextures[i]; for (int matIdx = 0; matIdx < matPropsTextureSet.matsAndGOs.mats.Count; matIdx++) { if (matPropsTextureSet.matsAndGOs.gos.Count > 0) { matPropsTextureSet.matsAndGOs.mats[matIdx].objName = matPropsTextureSet.matsAndGOs.gos[0].name; } else if (matPropsTextureSet.ts[0] != null) { matPropsTextureSet.matsAndGOs.mats[matIdx].objName = string.Format("[objWithTx:{0} atlasBlock:{1} matIdx{2}]", matPropsTextureSet.ts[0].GetTexName(), i, matIdx); } else { matPropsTextureSet.matsAndGOs.mats[matIdx].objName = string.Format("[objWithTx:{0} atlasBlock:{1} matIdx{2}]", "Unknown", i, matIdx); } } matPropsTextureSet.CalcInitialFullSamplingRects(fixOutOfBoundsUVs); matPropsTextureSet.CalcMatAndUVSamplingRects(); } // need to calculate the srcSampleRect for the complete tiling in the atlas // for each material need to know what the subrect would be in the atlas if material UVRect was 0,0,1,1 and Merged uvRect was full tiling //需要为图集中的完整切片计算src SampleRect //对于每种材料,如果材料UVRect为0,0,1,1并且合并的uvRect为完整平铺,则需要知道该图集在图集中的位置 List <int> MarkedForDeletion = new List <int>(); for (int i = 0; i < distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet tx2 = distinctMaterialTextures[i]; for (int j = i + 1; j < distinctMaterialTextures.Count; j++) { MaterialPropTexturesSet tx1 = distinctMaterialTextures[j]; if (tx1.AllTexturesAreSameForMerge(tx2, _considerNonTextureProperties, resultMaterialTextureBlender)) { double accumulatedAreaCombined = 0f; double accumulatedAreaNotCombined = 0f; DRect encapsulatingRectMerged = new DRect(); int idxOfFirstNotNull = -1; for (int propIdx = 0; propIdx < tx2.ts.Length; propIdx++) { if (!tx2.ts[propIdx].isNull) { if (idxOfFirstNotNull == -1) { idxOfFirstNotNull = propIdx; } } } if (idxOfFirstNotNull != -1) { // only in here if all properties use the same tiling so don't need to worry about which propIdx we are dealing with //Get the rect that encapsulates all material and UV tiling for materials and meshes in tx1 //如果所有属性都使用相同的tiling,因此无需担心我们正在处理哪个propIdx //获取将所有材料和UV平铺封装为rect的rect在tx1中 DRect encapsulatingRect1 = tx1.matsAndGOs.mats[0].samplingRectMatAndUVTiling; for (int matIdx = 1; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { DRect tmpSsamplingRectMatAndUVTilingTx1 = tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling; encapsulatingRect1 = UVRectUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref tmpSsamplingRectMatAndUVTilingTx1); } //same for tx2 DRect encapsulatingRect2 = tx2.matsAndGOs.mats[0].samplingRectMatAndUVTiling; for (int matIdx = 1; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { DRect tmpSsamplingRectMatAndUVTilingTx2 = tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling; encapsulatingRect2 = UVRectUtility.GetEncapsulatingRectShifted(ref encapsulatingRect2, ref tmpSsamplingRectMatAndUVTilingTx2); } encapsulatingRectMerged = UVRectUtility.GetEncapsulatingRectShifted(ref encapsulatingRect1, ref encapsulatingRect2); accumulatedAreaCombined += encapsulatingRectMerged.width * encapsulatingRectMerged.height; accumulatedAreaNotCombined += encapsulatingRect1.width * encapsulatingRect1.height + encapsulatingRect2.width * encapsulatingRect2.height; } else { encapsulatingRectMerged = new DRect(0f, 0f, 1f, 1f); } //the distinct material textures may overlap. //if the area of these rectangles combined is less than the sum of these areas of these rectangles then merge these distinctMaterialTextures if (accumulatedAreaCombined < accumulatedAreaNotCombined) { // merge tx2 into tx1 numMerged++; StringBuilder sb = null; sb = new StringBuilder(); sb.AppendFormat("About To Merge:\n TextureSet1 {0}\n TextureSet2 {1}\n", tx1.GetDescription(), tx2.GetDescription()); for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect()); } for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx2 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx2.matsAndGOs.mats[matIdx].mat, tx2.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx2.ts[0].GetEncapsulatingSamplingRect()); } //copy game objects over for (int k = 0; k < tx2.matsAndGOs.gos.Count; k++) { if (!tx1.matsAndGOs.gos.Contains(tx2.matsAndGOs.gos[k])) { tx1.matsAndGOs.gos.Add(tx2.matsAndGOs.gos[k]); } } //copy materials over from tx2 to tx1 for (int matIdx = 0; matIdx < tx2.matsAndGOs.mats.Count; matIdx++) { tx1.matsAndGOs.mats.Add(tx2.matsAndGOs.mats[matIdx]); } tx1.SetEncapsulatingSamplingRectWhenMergingTexSets(encapsulatingRectMerged); if (!MarkedForDeletion.Contains(i)) { MarkedForDeletion.Add(i); } sb.AppendFormat("=== After Merge TextureSet {0}\n", tx1.GetDescription()); for (int matIdx = 0; matIdx < tx1.matsAndGOs.mats.Count; matIdx++) { sb.AppendFormat("tx1 Mat {0} matAndMeshUVRect {1} fullSamplingRect {2}\n", tx1.matsAndGOs.mats[matIdx].mat, tx1.matsAndGOs.mats[matIdx].samplingRectMatAndUVTiling, tx1.ts[0].GetEncapsulatingSamplingRect()); } //Integrity check that sampling rects fit into enapsulating rects if (MeshBakerRoot.DO_INTEGRITY_CHECKS) { if (MeshBakerRoot.DO_INTEGRITY_CHECKS) { DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures); } } Debug.Log(sb.ToString()); break; Debug.Log(string.Format("Considered merging {0} and {1} but there was not enough overlap. It is more efficient to bake these to separate rectangles.", tx1.GetDescription(), tx2.GetDescription())); } } } //remove distinctMaterialTextures that were merged for (int j = MarkedForDeletion.Count - 1; j >= 0; j--) { distinctMaterialTextures.RemoveAt(MarkedForDeletion[j]); } MarkedForDeletion.Clear(); Debug.Log(string.Format("MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects complete merged {0} now have {1}", numMerged, distinctMaterialTextures.Count)); if (MeshBakerRoot.DO_INTEGRITY_CHECKS) { DoIntegrityCheckMergedEncapsulatingSamplingRects(distinctMaterialTextures); } } }
/// <summary> /// 第一步: /// 写入 TexturePipelineData 的 MaterialPropTexturesSet 列表,和 usedObjsToMesh 列表 /// 每个TexSet在 Atlas 中都是一个矩形。 /// 如果 allowedMaterialsFilter (过滤器)为空,那么将收集 allObjsToMesh 上的所有材质,usedObjsToMesh 将与allObjsToMesh相同 /// 否则,将仅包括allowedMaterialsFilter中的材料,而usedObjsToMesh将是使用这些材料的objs。 /// </summary> internal static IEnumerator __Step1_CollectDistinctMatTexturesAndUsedObjects(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, TexturePipelineData data, EditorMethodsInterface textureEditorMethods, List <GameObject> usedObjsToMesh) { // Collect distinct list of textures to combine from the materials on objsToCombine // 收集UsedObjects上不同的材质纹理 bool outOfBoundsUVs = false; Dictionary <int, MeshAnalysisResult[]> meshAnalysisResultsCache = new Dictionary <int, 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 (obj == null) { Debug.LogError("合并游戏物体列表中包含空物体"); result.success = false; yield break; } Mesh sharedMesh = MeshBakerUtility.GetMesh(obj); if (sharedMesh == null) { Debug.LogError("游戏物体 " + obj.name + " 网格为空"); result.success = false; yield break; } Material[] sharedMaterials = MeshBakerUtility.GetGOMaterials(obj); if (sharedMaterials.Length == 0) { Debug.LogError("游戏物体 " + obj.name + " 材质为空."); result.success = false; yield break; } //analyze mesh or grab cached result of previous analysis, stores one result for each submesh //处理网格数据 MeshAnalysisResult[] meshAnalysisResults;//每个游戏物体的主网格子网格数据数组 if (!meshAnalysisResultsCache.TryGetValue(sharedMesh.GetInstanceID(), out meshAnalysisResults)) { meshAnalysisResults = new MeshAnalysisResult[sharedMesh.subMeshCount]; for (int j = 0; j < sharedMesh.subMeshCount; j++) { MeshBakerUtility.hasOutOfBoundsUVs(sharedMesh, ref meshAnalysisResults[j], j); if (data._normalizeTexelDensity) { meshAnalysisResults[j].submeshArea = GetSubmeshArea(sharedMesh, j); } if (data._fixOutOfBoundsUVs && !meshAnalysisResults[j].hasUVs) { meshAnalysisResults[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(), meshAnalysisResults); } if (data._fixOutOfBoundsUVs) { Debug.Log("Mesh Analysis for object " + obj + " numSubmesh=" + meshAnalysisResults.Length + " HasOBUV=" + meshAnalysisResults[0].hasOutOfBoundsUVs + " UVrectSubmesh0=" + meshAnalysisResults[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]; // 材质过滤器 if (data.allowedMaterialsFilter != null && !data.allowedMaterialsFilter.Contains(mat)) { continue; } outOfBoundsUVs = outOfBoundsUVs || meshAnalysisResults[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 (!MeshBakerUtility.AreAllSharedMaterialsDistinct(sharedMaterials)) { Debug.LogWarning("游戏物体 " + obj.name + " 使用相同的材质在多个子网格. " + "可能生成奇怪的 resultAtlasesAndRects,尤其是与 _fixOutOfBoundsUVs 为 true 时"); } } //材质属性所用到的 Texutre MaterialPropTexture[] mts = new MaterialPropTexture[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; 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) { //TextureFormat 验证 tx = txx; TextureFormat f = ((Texture2D)tx).format; bool isNormalMap = false; if (!Application.isPlaying && textureEditorMethods != null) { isNormalMap = textureEditorMethods.IsNormalMap((Texture2D)tx); } if ((f == TextureFormat.ARGB32 || f == TextureFormat.RGBA32 || f == TextureFormat.BGRA32 || f == TextureFormat.RGB24 || f == TextureFormat.Alpha8) && !isNormalMap) //DXT5 does not work { //可使用 } else { //TRIED to copy texture using tex2.SetPixels(tex1.GetPixels()) but bug in 3.5 means DTX1 and 5 compressed textures come out skewe //尝试使用tex2.SetPixels(tex1.GetPixels())复制纹理,但是3.5中的bug意味着DTX1和5压缩纹理出现扭曲 if (Application.isPlaying && data._packingAlgorithm != PackingAlgorithmEnum.MeshBakerTexturePacker_Fast) { Debug.LogWarning("合并列表中,游戏物体 " + obj.name + " 所使用的 Texture " + tx.name + " 使用的格式 " + f + "不是: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 或 DXT. " + "无法在运行时重新设置尺寸" + "If format says 'compressed' try changing it to 'truecolor'"); result.success = false; yield break; } else { tx = (Texture2D)mat.GetTexture(data.texPropertyNames[propIdx].name); } } } else { Debug.LogError("合并列表中,游戏物体 " + obj.name + " 渲染网格使用的 Texture 不是 Texture2D. "); result.success = false; yield break; } } //像素密度 if (tx != null && data._normalizeTexelDensity) { //不考虑平铺和UV采样超出范围 if (meshAnalysisResults[propIdx].submeshArea == 0) { texelDensity = 0f; } else { texelDensity = (tx.width * tx.height) / (meshAnalysisResults[propIdx].submeshArea); } } //规格,偏移 GetMaterialScaleAndOffset(mat, data.texPropertyNames[propIdx].name, out offset, out scale); } mts[propIdx] = new MaterialPropTexture(tx, offset, scale, texelDensity); } // 收集材质参数值的平均值 data.nonTexturePropertyBlender.CollectAverageValuesOfNonTextureProperties(data.resultMaterial, mat); Vector2 obUVscale = new Vector2(meshAnalysisResults[matIdx].uvRect.width, meshAnalysisResults[matIdx].uvRect.height); Vector2 obUVoffset = new Vector2(meshAnalysisResults[matIdx].uvRect.x, meshAnalysisResults[matIdx].uvRect.y); //Add to distinct set of textures if not already there TextureTilingTreatment tilingTreatment = TextureTilingTreatment.none; if (data._fixOutOfBoundsUVs) { tilingTreatment = TextureTilingTreatment.considerUVs; } //合并信息 distinctMaterialTextures 数据设置 //材质各参数 Texture,及 UV 偏移数据映射 MaterialPropTexturesSet setOfTexs = new MaterialPropTexturesSet(mts, obUVoffset, obUVscale, tilingTreatment); //one of these per submesh //材质及各变化参数Rect 数据 MatAndTransformToMerged matt = new MatAndTransformToMerged(new DRect(obUVoffset, obUVscale), data._fixOutOfBoundsUVs, mat); setOfTexs.matsAndGOs.mats.Add(matt); MaterialPropTexturesSet 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); } } } } Debug.Log(string.Format("第一阶段完成;" + "参与合并的游戏物体的不同材质,各自包含与shader属性对应的不同的纹理,收集到 {0} 组 textures,即 {0} 个不同的材质," + "fixOutOfBoundsUV:{1} " + "considerNonTextureProperties:{2}", data.distinctMaterialTextures.Count, data._fixOutOfBoundsUVs, data._considerNonTextureProperties)); if (data.distinctMaterialTextures.Count == 0) { Debug.LogError("None of the source object materials matched any of the allowed materials for submesh with result material: " + data.resultMaterial); result.success = false; yield break; } TextureCombinerMerging merger = new TextureCombinerMerging(data._considerNonTextureProperties, data.nonTexturePropertyBlender, data._fixOutOfBoundsUVs); merger.MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(data.distinctMaterialTextures); yield break; }
/// <summary> /// Texture 合并管线第 3 步,创建 Atlas 并保存资源 /// </summary> /// <returns></returns> internal static IEnumerator __Step3_BuildAndSaveAtlasesAndStoreResults(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, TexturePipelineData data, TextureCombineHandler combiner, ITextureCombinerPacker packer, AtlasPackingResult atlasPackingResult, EditorMethodsInterface textureEditorMethods, AtlasesAndRects resultAtlasesAndRects) { //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]; //StringBuilder report = GenerateReport(data); //创建图集 yield return(packer.CreateAtlases(progressInfo, data, combiner, atlasPackingResult, atlases, textureEditorMethods)); data.nonTexturePropertyBlender.AdjustNonTextureProperties(data.resultMaterial, data.texPropertyNames, data.distinctMaterialTextures, 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()); List <MaterialAndUVRect> mat2rect_map = new List <MaterialAndUVRect>(); for (int i = 0; i < data.distinctMaterialTextures.Count; i++) { MaterialPropTexturesSet texSet = data.distinctMaterialTextures[i]; List <MatAndTransformToMerged> mats = texSet.matsAndGOs.mats; Rect allPropsUseSameTiling_encapsulatingSamplingRect; Rect propsUseDifferntTiling_obUVRect; texSet.GetRectsForTextureBakeResults(out allPropsUseSameTiling_encapsulatingSamplingRect, out propsUseDifferntTiling_obUVRect); for (int j = 0; j < mats.Count; j++) { Rect allPropsUseSameTiling_sourceMaterialTiling = texSet.GetMaterialTilingRectForTextureBakerResults(j); MaterialAndUVRect key = new MaterialAndUVRect( mats[j].mat, atlasPackingResult.rects[i], texSet.allTexturesUseSameMatTiling, allPropsUseSameTiling_sourceMaterialTiling, allPropsUseSameTiling_encapsulatingSamplingRect, propsUseDifferntTiling_obUVRect, texSet.tilingTreatment, mats[j].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.originMatToRect_map = mat2rect_map; if (progressInfo != null) { progressInfo("Restoring Texture Formats & Read Flags", .8f); } combiner._destroyAllTemporaryTextures(); if (textureEditorMethods != null) { textureEditorMethods.RestoreReadFlagsAndFormats(progressInfo); } //if (report != null) // Debug.Log(report.ToString()); yield break; }
//第二步:计算每个材质的属性对应的 Textures 统一尺寸 //每种材质(_mainTex,凹凸,Spec ect ...)中的纹理必须大小相同 //计算要使用的最佳尺寸。 考虑平铺 //如果图集中只有一种纹理会使用原始大小 internal static IEnumerator _Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, TexturePipelineData data, EditorMethodsInterface textureEditorMethods) { MaterialPropTexture.readyToBuildAtlases = true; data.allTexturesAreNullAndSameColor = CalculateAllTexturesAreNullAndSameColor(data); //calculate size of rectangles in atlas //计算 atlas 矩形尺寸 int _padding = data._atlasPadding; if (data.distinctMaterialTextures.Count == 1 && data._fixOutOfBoundsUVs == false && data._considerNonTextureProperties == false) { Debug.Log("所有游戏物体使用相同的材质.将使用 Original textures ."); _padding = 0; data.distinctMaterialTextures[0].SetThisIsOnlyTexSetInAtlasTrue(); data.distinctMaterialTextures[0].SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(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++) { Debug.Log("为 TexSet " + i + " of " + data.distinctMaterialTextures.Count + "计算合适的尺寸"); MaterialPropTexturesSet 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"); //在 MaterialPropTexturesSet 中所有 MaterialPropTextures 应为相同尺寸 for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++) { if (_ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor)) { MaterialPropTexture matTex = txs.ts[propIdx]; Debug.Log(string.Format("为 texSet {0} ,property {1} 计算合适尺寸", i, data.texPropertyNames[propIdx].name)); if (!matTex.matTilingRect.size.Equals(Vector2.one) && data.distinctMaterialTextures.Count > 1) { 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) { 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); 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 = GetAdjustedForScaleAndOffset2Dimensions(matTex, txs.obUVoffset, txs.obUVscale, data); if ((int)(dim.x * dim.y) > tWidth * tHeight) { Debug.Log(" 材质texture " + matTex.GetTexName() + " " + dim + " 需要比" + 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; } } Debug.Log("Ideal size is " + tWidth + " " + tHeight); txs.idealWidth = tWidth; txs.idealHeight = tHeight; } data._atlasPadding = _padding; yield break; }