Unity中在3D空间内显示图片并保持宽高比
嘿Akshay,我来帮你搞定Unity里Plane显示图片保持宽高比的问题!下面几个实用方法应该能解决你的挤压困扰:
解决Unity Plane图片挤压问题的方案
方法1:手动调整Plane尺寸(适合静态已知图片)
如果你提前知道图片的宽高比,可以直接手动调整Plane的缩放来匹配:
- 先算出图片的宽高比:
宽高比 = 图片宽度 / 图片高度(比如1920x1080的图片比例就是16/9≈1.777) - 选中Plane,在Inspector面板找到Transform组件的Scale属性
- 注意:Plane默认的Mesh实际尺寸是10x10单位(X轴宽10,Y轴高10),所以我们只需要调整Scale的X或Y值来匹配比例:
- 保持Y轴缩放为1,把X轴缩放设为你的图片宽高比(比如1.777),这样Plane的宽高比就和图片一致,纹理不会变形
- 如果想固定Plane的宽度,比如让宽度保持10单位,那可以计算Y轴缩放为
1 / 宽高比,同样能保持比例
方法2:代码动态调整(适合网络下载的动态图片)
如果图片是从网络下载的,没法提前知道比例,用代码自动调整是最优解。下面是一个完整的C#脚本示例:
using UnityEngine; using UnityEngine.Networking; public class DynamicImageHandler : MonoBehaviour { public string targetImageUrl; private Renderer _planeRenderer; void Start() { _planeRenderer = GetComponent<Renderer>(); StartCoroutine(DownloadAndAdjustImage()); } IEnumerator DownloadAndAdjustImage() { using (UnityWebRequest webRequest = UnityWebRequestTexture.GetTexture(targetImageUrl)) { yield return webRequest.SendWebRequest(); if (webRequest.result != UnityWebRequest.Result.Success) { Debug.LogError($"图片下载失败:{webRequest.error}"); yield break; } // 获取下载的纹理 Texture2D downloadedTexture = ((DownloadHandlerTexture)webRequest.downloadHandler).texture; _planeRenderer.material.mainTexture = downloadedTexture; // 计算图片宽高比并调整Plane缩放 float imageAspectRatio = (float)downloadedTexture.width / downloadedTexture.height; // 保持Y轴缩放为1,X轴按比例适配 transform.localScale = new Vector3(imageAspectRatio, 1f, 1f); // 如果你想固定Plane的总宽度(比如设为10单位),可以用下面的代码替换上面的缩放设置: // float fixedWidth = 10f; // float calculatedHeight = fixedWidth / imageAspectRatio; // transform.localScale = new Vector3(fixedWidth / 10f, calculatedHeight / 10f, 1f); } } }
- 把这个脚本挂在你的Plane对象上,填入目标图片的URL即可。运行后会自动下载图片,计算比例并调整Plane缩放,完全避免挤压。
方法3:调整材质UV坐标(固定Plane尺寸的场景)
如果需要保持Plane的大小不变,只想让图片在Plane内居中显示并保持比例(多余区域留空),可以通过调整材质的UV来实现:
- 先给Plane替换一个Unlit/Texture材质(默认的Standard材质也可以,但Unlit更适合显示2D图片)
- 挂载下面的脚本自动调整UV:
using UnityEngine; public class UVAspectRatioFixer : MonoBehaviour { private Renderer _planeRenderer; private Texture2D _currentTexture; void Start() { _planeRenderer = GetComponent<Renderer>(); _currentTexture = _planeRenderer.material.mainTexture as Texture2D; AdjustUVToFit(); } void AdjustUVToFit() { if (_currentTexture == null) return; // 计算Plane和图片的宽高比 float planeAspect = transform.localScale.x / transform.localScale.y; float imageAspect = (float)_currentTexture.width / _currentTexture.height; Vector2 uvScale = Vector2.one; Vector2 uvOffset = Vector2.zero; if (planeAspect > imageAspect) { // Plane比图片宽,缩小图片的X轴缩放,左右留空 uvScale.x = imageAspect / planeAspect; uvOffset.x = (1 - uvScale.x) / 2; } else { // Plane比图片高,缩小图片的Y轴缩放,上下留空 uvScale.y = planeAspect / imageAspect; uvOffset.y = (1 - uvScale.y) / 2; } // 应用UV调整到材质 _planeRenderer.material.mainTextureScale = uvScale; _planeRenderer.material.mainTextureOffset = uvOffset; } // 如果动态替换图片,调用这个方法更新UV public void UpdateDisplayedTexture(Texture2D newTexture) { _currentTexture = newTexture; _planeRenderer.material.mainTexture = newTexture; AdjustUVToFit(); } }
- 这个方法下Plane的尺寸不会改变,图片会自动居中,多余的区域会显示材质的底色(你可以把材质的颜色设为透明或者和场景背景一致)。
内容的提问来源于stack exchange,提问作者Akshay Shah




