官方的api可以直接获取预览图像,如下所示:
Tex=AssetPreview.GetAssetPreview(Object m)as Texture;
但是如果prefab是组合体的话(即一个prefab下包含2个或多个子物体),便只返回null。可以算是unity的一个bug吧。
所以需要自己写函数来实现prefab图像预览。
思路是将Prefab实例化到场景,并利用RenderTexture进行摄像机截取图像作为预览图像,代码如下:
1 /// <summary> 2 /// 获取预览图象 3 /// </summary> 4 /// <param name="obj"></param> 5 /// <returns></returns> 6 private Texture GetAssetPreview(GameObject obj) 7 { 8 GameObject clone = GameObject.Instantiate(obj); 9 Transform cloneTransform = clone.transform; 10 cloneTransform.position = new Vector3(-1000, -1000, -1000); 11 //cloneTransform.localRotation = new Quaternion(0, 0, 0, 1); 12 13 Transform[] all = clone.GetComponentsInChildren<Transform>(); 14 foreach (Transform trans in all) 15 { 16 trans.gameObject.layer = 21; 17 } 18 19 Bounds bounds = GetBounds(clone); 20 Vector3 Min = bounds.min; 21 Vector3 Max = bounds.max; 22 GameObject cameraObj = new GameObject("render camera"); 23 cameraObj.transform.position = new Vector3(cloneTransform.position.x, (Max.y + Min.y) / 2f, Max.z + (Max.z - Min.z)); 24 25 Vector3 center = new Vector3(cloneTransform.position.x, (Max.y + Min.y) / 2f, cloneTransform.position.z); 26 27 cameraObj.transform.LookAt(center); 28 29 Camera renderCamera = cameraObj.AddComponent<Camera>(); 30 renderCamera.backgroundColor = new Color(0.8f, 0.8f, 0.8f, 1f); 31 renderCamera.clearFlags = CameraClearFlags.Color; 32 renderCamera.cameraType = CameraType.Preview; 33 renderCamera.cullingMask = 1 << 21; 34 int angle = (int)(Mathf.Atan2((Max.y - Min.y) / 2, (Max.z - Min.z)) * 180 / 3.1415f * 2); 35 renderCamera.fieldOfView = angle; 36 37 RenderTexture texture = new RenderTexture(64, 64, 0, RenderTextureFormat.Default); 38 renderCamera.targetTexture = texture; 39 40 renderCamera.RenderDontRestore(); 41 42 RenderTexture tex = new RenderTexture(64, 64, 0, RenderTextureFormat.Default); 43 Graphics.Blit(texture, tex); 44 45 Object.DestroyImmediate(clone); 46 Object.DestroyImmediate(cameraObj); 47 48 return tex; 49 } 50 /// <summary> 51 /// 获得某物体的bounds 52 /// </summary> 53 /// <param name="obj"></param> 54 private Bounds GetBounds(GameObject obj) 55 { 56 Vector3 Min = new Vector3(99999, 99999, 99999); 57 Vector3 Max = new Vector3(-99999, -99999, -99999); 58 MeshRenderer[] renders = obj.GetComponentsInChildren<MeshRenderer>(); 59 for (int i = 0; i < renders.Length; i++) 60 { 61 if (renders[i].bounds.min.x < Min.x) 62 Min.x = renders[i].bounds.min.x; 63 if (renders[i].bounds.min.y < Min.y) 64 Min.y = renders[i].bounds.min.y; 65 if (renders[i].bounds.min.z < Min.z) 66 Min.z = renders[i].bounds.min.z; 67 68 if (renders[i].bounds.max.x > Max.x) 69 Max.x = renders[i].bounds.max.x; 70 if (renders[i].bounds.max.y > Max.y) 71 Max.y = renders[i].bounds.max.y; 72 if (renders[i].bounds.max.z > Max.z) 73 Max.z = renders[i].bounds.max.z; 74 } 75 76 Vector3 center = (Min + Max) / 2; 77 Vector3 size = new Vector3(Max.x - Min.x, Max.y - Min.y, Max.z - Min.z); 78 return new Bounds(center, size); 79 }
后补:unity在2017.2版本已经修复了这个问题,可以放心用Tex=AssetPreview.GetAssetPreview(Object m)as Texture了。
感谢博友@跳出定向思维的发现,之前的unity旧版本也可以通过给prefab添加标签来解决问题,添加了任意标签后就可以使用自带的获取预览api了。