Files
Fishing2/Assets/Scripts/UI/Common/ModelViewer/ModelViewRenderImage.cs
2025-10-29 11:31:26 +08:00

288 lines
8.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using FairyGUI;
using FairyGUI.Utils;
using System.Collections;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using Object = UnityEngine.Object;
namespace NBF
{
[Serializable]
public class ModelViewRenderImage
{
public Transform modelRoot { get; private set; }
public Camera Camera => _camera;
public RenderTexture RT => _renderTexture;
public ModelViewerSettings ViewerSettings { get; private set; }
Camera _camera;
Image _image;
Transform _root;
Transform _background;
Transform _model;
RenderTexture _renderTexture;
int _width;
int _height;
bool _cacheTexture;
Vector3 _rotating;
const int RENDER_LAYER = 0;
const int HIDDEN_LAYER = 10;
public ModelViewRenderImage(GGraph holder)
{
_width = (int)holder.width;
_height = (int)holder.height;
_cacheTexture = true;
_image = new Image();
holder.SetNativeObject(_image);
_root = new GameObject("RenderImage").transform;
_root.transform.position = Vector3.zero;
// _root.SetParent(_camera.transform, false);
SetLayer(_root.gameObject, HIDDEN_LAYER);
Object.DontDestroyOnLoad(_root.gameObject);
Object prefab = Resources.Load("RenderTexture/RenderImageCamera");
GameObject go = (GameObject)Object.Instantiate(prefab, _root, false);
_camera = go.GetComponent<Camera>();
_camera.transform.position = Vector3.zero;
_camera.cullingMask = 1 << RENDER_LAYER;
_camera.enabled = false;
Object.DontDestroyOnLoad(_camera.gameObject);
modelRoot = new GameObject("model_root").transform;
modelRoot.SetParent(_root, false);
_background = new GameObject("background").transform;
_background.SetParent(_root, false);
_image.onAddedToStage.Add(OnAddedToStage);
_image.onRemovedFromStage.Add(OnRemoveFromStage);
// _viewerSettings = new ModelViewerSettings();
if (_image.stage != null)
OnAddedToStage();
else
_camera.gameObject.SetActive(false);
}
public void LoadModel(string model, ModelViewerSettings settings)
{
this.UnloadModel();
ViewerSettings = settings;
Object prefab = Resources.Load(model);
if(prefab == null) return;
GameObject go = ((GameObject)Object.Instantiate(prefab));
var joint = go.GetComponent<Joint>();
if (joint != null)
{
Object.Destroy(joint);
}
_model = go.transform;
_model.SetParent(this.modelRoot, false);
_model.localPosition = Vector3.zero;
_model.localScale = Vector3.one;
_model.localEulerAngles = Vector3.zero;
if (ViewerSettings == null)
{
ViewerSettings = new ModelViewerSettings();
ModelViewerUtils.InitSetting(go, ViewerSettings);
}
Review();
}
public void UnloadModel()
{
if (_model != null)
{
_model.gameObject.SetActive(false);
Object.Destroy(_model.gameObject);
_model = null;
}
_rotating = Vector3.zero;
}
public void Review()
{
_model.position = ViewerSettings.objectPosition;
_model.localScale = ViewerSettings.objectScale;
_model.eulerAngles = ViewerSettings.objectRotation;
_camera.clearFlags = CameraClearFlags.Nothing;
_camera.backgroundColor = new Color(0, 0, 0, 0); // 完全透明
_camera.transform.position = ViewerSettings.cameraPosition;
_camera.transform.LookAt(ViewerSettings.cameraTarget);
_camera.orthographic = ViewerSettings.cameraOrtho;
_camera.orthographicSize = ViewerSettings.cameraSize;
_camera.orthographicSize /= ViewerSettings.camerasScaleFactor;
_camera.fieldOfView = ViewerSettings.cameraFov;
float fov = 2 * Mathf.Rad2Deg * Mathf.Atan2(
Mathf.Tan(_camera.fieldOfView * Mathf.Deg2Rad / 2), ViewerSettings.camerasScaleFactor
);
if (fov < 0)
fov += 180;
_camera.fieldOfView = fov;
_camera.nearClipPlane = 0.001f;
_camera.farClipPlane = 10000;
_camera.depthTextureMode = DepthTextureMode.Depth;
_camera.clearFlags = CameraClearFlags.Color;
_camera.GetUniversalAdditionalCameraData().renderPostProcessing = false; //URP only
}
public void Dispose()
{
UnloadModel();
Object.Destroy(_camera.gameObject);
DestroyTexture();
_image.Dispose();
_image = null;
}
void CreateTexture()
{
if (_renderTexture != null)
return;
_renderTexture = new RenderTexture(1024, 1024, 24, RenderTextureFormat.ARGB32)
{
antiAliasing = 8,
filterMode = FilterMode.Bilinear,
anisoLevel = 0,
useMipMap = false
};
// _renderTexture.Create();
_image.texture = new NTexture(_renderTexture);
_image.shader = "Unlit/Transparent";
}
void DestroyTexture()
{
if (_renderTexture != null)
{
Object.Destroy(_renderTexture);
_renderTexture = null;
_image.texture = null;
}
}
void OnAddedToStage()
{
if (_renderTexture == null)
CreateTexture();
Timers.inst.AddUpdate(Render);
_camera.gameObject.SetActive(true);
Render();
}
void OnRemoveFromStage()
{
if (!_cacheTexture)
DestroyTexture();
Timers.inst.Remove(Render);
_camera.gameObject.SetActive(false);
}
void Render(object param = null)
{
if (_rotating != Vector3.zero && this.modelRoot != null)
{
// 使用 Quaternion 来避免欧拉角带来的问题
modelRoot.Rotate(_rotating, Space.World);
}
SetLayer(_root.gameObject, RENDER_LAYER);
_camera.targetTexture = _renderTexture;
RenderTexture old = RenderTexture.active;
RenderTexture.active = _renderTexture;
GL.Clear(true, true, Color.clear);
_camera.Render();
RenderTexture.active = old;
SetLayer(_root.gameObject, HIDDEN_LAYER);
UpdateDebugSave();
}
void SetLayer(GameObject go, int layer)
{
Transform[] transforms = go.GetComponentsInChildren<Transform>(true);
foreach (Transform t in transforms)
{
t.gameObject.layer = layer;
}
}
#region
public void StartRotate(Vector3 delta)
{
_rotating = delta;
}
public void StopRotate()
{
_rotating = Vector3.zero;
}
#endregion
#region MyRegion
void UpdateDebugSave()
{
if (Input.GetKeyDown(KeyCode.F9))
{
SaveRenderTextureToPNG(_renderTexture, "RenderTextureDebug.png");
}
}
void SaveRenderTextureToPNG(RenderTexture rt, string fileName)
{
if (rt == null)
{
Debug.LogWarning("RenderTexture 为 null无法保存。");
return;
}
RenderTexture current = RenderTexture.active;
RenderTexture.active = rt;
Texture2D tex = new Texture2D(rt.width, rt.height, TextureFormat.RGBA32, false);
tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
tex.Apply();
byte[] bytes = tex.EncodeToPNG();
string path = System.IO.Path.Combine(Application.dataPath, "../" + fileName);
System.IO.File.WriteAllBytes(path, bytes);
Debug.Log($"✅ RenderTexture 已保存到: {path}");
UnityEngine.Object.Destroy(tex);
RenderTexture.active = current;
}
#endregion
}
}