src | 源纹理。 |
dst | 目标纹理。 |
srcElement | 要从中进行复制的源纹理中的元素。例如,Cubemap 中的 CubemapFace 或纹理数组中的切片。如果 src 是 2D 纹理,则将该值设置为 0 。 |
srcMip | 要从中进行复制的 mipmap 级别。范围从 0 到纹理的 Texture.mipmapCount 或 GraphicsTextureDescriptor.mipCount。默认值为 0 。 |
dstElement | 要进行复制的目的地纹理中的元素。例如,Cubemap 中的 CubemapFace 或纹理数组中的切片。如果 `dst` 是 2D 纹理,则将该值设置为 0 。 |
dstMip | 要写入的 mipmap 级别。范围从 0 到纹理的 Texture.mipmapCount 或 GraphicsTextureDescriptor.mipCount。默认值为 0 。 |
srcX | 要从中进行复制的 src 的起始 x 坐标。 0 是纹理的左侧。 |
srcY | 要从中进行复制的 src 的起始 y 坐标。 0 是纹理的底部。 |
srcWidth | 要进行复制的 src 的宽度。 |
srcHeight | 要进行复制的 src 的高度。 |
dstX | 要进行复制的 dst 的 x 坐标。 |
dstY | 要进行复制的 dst 的 y 坐标。 |
将像素数据从一个纹理复制到另一个纹理。
此方法在 GPU 上将像素数据从一个纹理复制到另一个纹理。如果为 src
和 dst
Texture 参数均将 Texture.isReadable 设置为 true
,该方法还会尝试通过在 dst
纹理上运行 CopyPixels
来在 CPU 上复制像素数据。
如果您将 Texture.isReadable 设置为 false
或将 GraphicsTexture 用于 src
和 dst
,则像素数据将不会在 CPU 上复制,并且 CopyTexture
将成为复制纹理最快的方法之一。但是,要使用 CopyTexture
,源纹理区域和目标纹理区域中以下内容必须相同
根据图形 API,你也许能够在不兼容的格式之间进行复制。例如,在某些 API 上,你可以在具有相同位宽的格式之间进行复制。
根据图形 API,你也许无法在不同类型的纹理之间进行复制。有关兼容性的详细信息,请参阅 SystemInfo.copyTextureSupport 和 CopyTextureSupport。
如果 src
是仅限深度的渲染目标,则必须复制整个纹理,而不是部分内容。仅限深度的渲染纹理将其颜色缓冲区设置为 颜色格式 的 None
,并将其深度缓冲区设置为有效的 RenderTexture.depthStencilFormat。深度图形纹理将其 格式 设置为具有深度组件的有效 GraphicsFormat。
当你使用 QualitySettings.globalTextureMipmapLimit、Texture2D.mipmapLimitGroup 和 Texture2D.ignoreMipmapLimit 时,纹理可以有各种各样的渐进贴图限制设置。这意味着你可能无法从一个渐进贴图等级复制到另一个等级,因为源纹理限制到一半分辨率,而目标纹理限制到四分之一分辨率。注意,这在 src
和 dst
设置为图形纹理时不适用,因为图形纹理的渐进贴图数有限制,并且只表示当前加载的渐进贴图等级。
如果你需要在具有不同渐进贴图限制设置的纹理之间复制渐进贴图,请使用基于区域的重载。此重载根据源纹理的渐进贴图限制设置调整源矩形,根据目标的渐进贴图限制设置调整目标偏移。例如,从位置 16,16 向位置 32,32 复制 128x128 的区域,基于全局纹理渐进贴图限制、源纹理类型和目标纹理类型,会出现各种各样的行为。
以下示例演示了在 Texture2Ds 具有渐进贴图限制时,如何从 Texture2DArray 复制或向 Texture2DArray 复制
using UnityEngine;
public class CopyTextureSample : MonoBehaviour { // Sample to copy all available mips: inTex -> outArray (no mipmap limits) -> outTex [SerializeField] Texture2D inTex; [SerializeField] Texture2DArray outArray; [SerializeField] Texture2D outTex; [SerializeField] bool considerMipmapLimits;
void Start() { int width = inTex.width; int height = inTex.width;
outArray = new Texture2DArray(width, height, 1, inTex.format, true); outTex = new Texture2D(width, height, inTex.format, true);
if (!considerMipmapLimits) { // Texture2D -> Texture2DArray // Global Mipmap Limit: "1: Half Resolution" => copies into mips that are now too large; will copy each mip of inTex into a quarter of outArray for (int mip = 0; mip < inTex.mipmapCount; ++mip) { int copyWidth = width >> mip; int copyHeight = height >> mip; Graphics.CopyTexture(inTex, 0, mip, 0, 0, copyWidth, copyHeight, outArray, 0, mip, 0, 0); }
// Texture2DArray -> Texture2D // Global Mipmap Limit: "1: Half Resolution" => errors, since we try to copy into mips that are now too small for (int mip = 0; mip < outArray.mipmapCount; ++mip) { int copyWidth = width >> mip; int copyHeight = height >> mip; Graphics.CopyTexture(outArray, 0, mip, 0, 0, copyWidth, copyHeight, outTex, 0, mip, 0, 0); } } else // considering mipmap limits { int globalMipmapLimit = QualitySettings.globalTextureMipmapLimit;
// Texture2D -> Texture2DArray // Global Mipmap Limit: "1: Half Resolution" => mip0 of outArray is not written to, other mips copy as expected // (ALTERNATIVE: if outArray creation already considered globalMipmapLimit for its dimensions, // the CopyTexture call can ignore globalMipmapLimit since the mips will line up again) for (int mip = 0; mip < inTex.mipmapCount - globalMipmapLimit; ++mip) { int copyWidth = width >> mip; int copyHeight = height >> mip; int srcMip = mip; int dstMip = mip + globalMipmapLimit; Graphics.CopyTexture(inTex, 0, srcMip, 0, 0, copyWidth, copyHeight, outArray, 0, dstMip, 0, 0); }
// Texture2DArray -> Texture2D // Global Mipmap Limit: "1: Half Resolution" => mip0 of outArray is not copied (but outTex does not upload it to GPU anyway) for (int mip = globalMipmapLimit; mip < outArray.mipmapCount; ++mip) { int copyWidth = width >> mip; int copyHeight = height >> mip; int srcMip = mip; int dstMip = mip - globalMipmapLimit; Graphics.CopyTexture(outArray, 0, srcMip, 0, 0, copyWidth, copyHeight, outTex, 0, dstMip, 0, 0); } } } }
Mipmap 等级参数经常引用纹理当前加载的 mipmap 等级(可通过 GraphicsTextureDescriptor.mipCount 找到该纹理的 Texture.graphicsTexture)。例如,如果全局纹理 mipmap 限制设置为 0,256x256 纹理的 mip 1 将引用 128x128 mip。但是,对于相同的纹理,如果全局纹理 mipmap 限制设置为 1,mip 1 将引用一个 64x64 mip。如果全局纹理 mipmap 限制设置为 2,则该相同纹理的 mip 1 将引用一个 32x32 mip(以此类推)。
这意味着你在使用 `CopyTexture` 时,多数情况下无需考虑 mipmap 限制设置。但是,如果你使用 纹理,并且源与目标的 mipmap 限制设置不同,你将需要调整这些设置。请记住,非 2D 纹理类型总是以完整分辨率上传到 GPU,因为它们不支持任何种类的 mipmap 限制设置。
已压缩纹理格式添加了一些限制来使用具有区域变体的 CopyTexture。例如,不适用 PVRTC 格式,因为它们不是基于块的(对于这些格式,你只能复制完整纹理或完整 mip 等级)。对于基于块的格式(例如 DXT、BCn、ETC),区域大小和坐标必须是压缩块大小(对于 DXT 为 4 个像素)的倍数。
即使你将 Texture.isReadable
设置为 true,此方法在仅复制已压缩纹理的一个区域时也不会复制 CPU 上的像素数据。
不要在 CopyTexture
之后使用 Texture2D.Apply 等 Apply
方法,因为你可能会将旧的或未定义的 CPU 纹理数据复制到 GPU。
附加资源:CopyTextureSupport、Texture2D.CopyPixels。