internal static Vector2 GetAdjustedForScaleAndOffset2Dimensions(MaterialPropTexture source, Vector2 obUVoffset, Vector2 obUVscale, TextureCombinePipelineData data) { 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 } } 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)); }
public override void CreateAtlases( TextureCombinePipelineData 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 (!TextureCombinePipeline.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(); 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 (textureEditorMethods != null) { textureEditorMethods.SetReadWriteFlag(t, true, true); } DRect samplingRect = texSet.ts[propIdx].GetEncapsulatingSamplingRect(); CopyScaledAndTiledToAtlas(texSet.ts[propIdx], texSet, property, samplingRect, x, y, ww, hh, packedAtlasRects.padding[texSetIdx], atlasPixels, isNormalMap, data, combiner); } 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 (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); } }
//第二步:计算每个材质的属性对应的 Textures 统一尺寸 //每种材质(_mainTex,凹凸,Spec ect ...)中的纹理必须大小相同 //计算要使用的最佳尺寸。 考虑平铺 //如果图集中只有一种纹理会使用原始大小 internal static void Step2_CalculateIdealSizesForTexturesInAtlasAndPadding( TextureCombinePipelineData data, EditorMethodsInterface textureEditorMethods) { MaterialPropTexture.readyToBuildAtlases = true; data.allTexturesAreNullAndSameColor = CalculateAllTexturesAreNullAndSameColor(data); //计算 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; }