Files
Fishing2/Assets/Scripts/UI/Common/ModelViewer/ModelViewRenderImage.cs
2025-10-29 22:41:47 +08:00

321 lines
9.6 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
// 在 ModelViewRenderImage 中添加新字段
private Vector2 _lastMousePosition;
private bool _isDragging;
public void StartRotate(Vector2 currentMousePosition)
{
_lastMousePosition = currentMousePosition;
_isDragging = true;
}
public void UpdateRotation(Vector2 currentMousePosition)
{
if (!_isDragging || modelRoot == null || _camera == null) return;
Vector2 delta = currentMousePosition - _lastMousePosition;
// 使用适中的灵敏度
float sensitivity = 0.2f;
float rotX = -delta.y * sensitivity;
float rotY = -delta.x * sensitivity;
Quaternion yRotation = Quaternion.AngleAxis(rotY, _camera.transform.up);
Quaternion xRotation = Quaternion.AngleAxis(rotX, _camera.transform.right);
// 组合旋转并应用
modelRoot.rotation = yRotation * xRotation * modelRoot.rotation;
_lastMousePosition = currentMousePosition;
}
public void StopRotate()
{
_isDragging = false;
}
// 重置到初始状态的方法
public void ResetToInitialRotation()
{
modelRoot.localRotation = Quaternion.identity;
_isDragging = false;
}
#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
}
}