模型预览功能

This commit is contained in:
2025-10-26 23:32:33 +08:00
parent 1c18e4a338
commit ce6cd8235f
370 changed files with 12735 additions and 10269 deletions

View File

@@ -0,0 +1,227 @@
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
{
private ModelViewerSettings _viewerSettings;
public Transform modelRoot { get; private set; }
Camera _camera;
Image _image;
Transform _root;
Transform _background;
Transform _model;
RenderTexture _renderTexture;
int _width;
int _height;
bool _cacheTexture;
float _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);
// ConfigurableJoint
_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)
{
this.UnloadModel();
Object prefab = Resources.Load(model);
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;
ModelViewerUtils.InitSetting(go, _viewerSettings);
Review();
}
public void UnloadModel()
{
if (_model != null)
{
_model.gameObject.SetActive(false);
Object.Destroy(_model.gameObject);
_model = null;
}
_rotating = 0;
}
public void Review()
{
_model.position = _viewerSettings.objectPosition;
_model.localScale = _viewerSettings.objectScale;
_model.eulerAngles = _viewerSettings.objectRotation;
_camera.clearFlags = CameraClearFlags.Nothing;
_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 = 1,
filterMode = FilterMode.Bilinear,
anisoLevel = 0,
useMipMap = false
};
_image.texture = new NTexture(_renderTexture);
_image.blendMode = BlendMode.Off;
}
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 != 0 && modelRoot != null)
{
Vector3 localRotation = modelRoot.localRotation.eulerAngles;
localRotation.y += _rotating;
modelRoot.localRotation = Quaternion.Euler(localRotation);
}
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);
}
void SetLayer(GameObject go, int layer)
{
Transform[] transforms = go.GetComponentsInChildren<Transform>(true);
foreach (Transform t in transforms)
{
t.gameObject.layer = layer;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 14ecd9c69c8a4eb28e8f102cca593c0b
timeCreated: 1761412504

View File

@@ -0,0 +1,27 @@
/**本脚本为自动生成每次生成会覆盖请勿手动修改生成插件文档及项目地址https://git.whoot.com/whoot-games/whoot.fguieditorplugin**/
using FairyGUI;
using FairyGUI.Utils;
using NBC;
namespace NBF
{
public partial class ModelViewer
{
public const string URL = "ui://6hgkvlauxd2fml";
public GGraph ModelHolder;
public GGraph TouchHolder;
public override void ConstructFromXML(XML xml)
{
base.ConstructFromXML(xml);
ModelHolder = (GGraph)GetChild("ModelHolder");
TouchHolder = (GGraph)GetChild("TouchHolder");
OnInited();
UILanguage.TrySetComponentLanguage(this);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d1f6b336c0f70ab428b9ab14c0f1bd6f

View File

@@ -0,0 +1,78 @@
// 本脚本只在不存在时会生成一次。组件逻辑写在当前脚本内。已存在不会再次生成覆盖
using UnityEngine;
using FairyGUI;
using NBC;
using NBF.Fishing2;
namespace NBF
{
public partial class ModelViewer : GComponent
{
ModelViewRenderImage _renderImage;
private void OnInited()
{
_renderImage = new ModelViewRenderImage(ModelHolder.asGraph);
TouchHolder.onRollOver.Set(OnFocusIn);
TouchHolder.onRollOut.Set(OnFocusOut);
Stage.inst.onMouseWheel.Add(OnMouseWheel);
}
public override void Dispose()
{
Stage.inst.onMouseWheel.Remove(OnMouseWheel);
_renderImage.Dispose();
base.Dispose();
}
public void SetData(uint itemId)
{
SetData(ItemConfig.Get(itemId));
}
public void SetData(ItemConfig itemConfig)
{
//Assets/Resources/gfx/baits/worm_01/worm_01.prefab
// _renderImage.LoadModel("gfx/baits/worm_01/worm_01");
_renderImage.LoadModel("gfx/" + itemConfig.Model);
// var model = PrefabsHelper.CreatePrefab("gfx/baits/worm_01/worm_01");
}
#region ()
private void SetRotateListening()
{
var dragObj = TouchHolder;
var gesture1 = new SwipeGesture(dragObj);
gesture1.onMove.Set(OnSwipeMove);
gesture1.onEnd.Set(OnSwipeEnd);
}
private void OnSwipeMove(EventContext context)
{
}
private void OnSwipeEnd(EventContext context)
{
}
private void OnFocusIn()
{
// _focus = true;
Log.Info("focus true");
}
private void OnFocusOut()
{
// _focus = false;
Log.Info("focus false");
}
private void OnMouseWheel(EventContext context)
{
}
#endregion
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c4925b571afa6b84382089b71d8603f2

View File

@@ -0,0 +1,148 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using UnityEngine;
using Color = UnityEngine.Color;
namespace NBF
{
[Serializable]
public class ModelViewerSettings
{
//Object Settings
public Vector3 objectPosition;
public Vector3 objectRotation;
public Vector3 objectScale;
//Hierarchy Settings
[NonSerialized] public Dictionary<string, bool> subObjectEnables;
public List<string> soeStrings;
public List<bool> soeBools;
//Camera Settings
public Vector3 cameraPosition;
public Vector3 cameraTarget;
public bool autoPosition;
public bool autoScale;
public bool cameraOrtho;
public float cameraFov;
public float cameraSize;
public float camerasScaleFactor;
public float perspLastScale;
//Lighting Settings
public Color lightColour;
public Vector3 lightDir;
public float lightIntensity;
public Color ambientLightColour;
//Animation Settings
public AnimationClip animationClip;
public float animationOffset;
public string animationPath;
//Post-Processing Settings
public List<Material> postProcessingMaterials;
public Dictionary<Material, String> materialDisplayNames;
public Dictionary<Material, bool> materialToggles;
public enum FixEdgesModes
{
None,
Regular,
WithDepthTexture
};
public FixEdgesModes fixEdgesMode;
public FilterMode filterMode;
public ModelViewerSettings()
{
//Do nothing
//---Initialise Icon---//
//Object Settings
objectPosition = Vector3.zero;
objectRotation = Vector3.zero;
objectScale = Vector3.one;
autoPosition = true;
//Hierarchy Settings
subObjectEnables = new Dictionary<string, bool>();
//Camera Settings
cameraPosition = new Vector3(1, Mathf.Sqrt(2), 1);
perspLastScale = 1;
cameraOrtho = true;
cameraFov = 60;
cameraSize = 5;
camerasScaleFactor = 1;
cameraTarget = Vector3.zero;
autoScale = true;
//Lighting Settings
ambientLightColour = Color.gray;
lightColour = Color.white;
lightDir = new Vector3(50, -30, 0);
lightIntensity = 1;
//Post-Processing Settings
postProcessingMaterials = new List<Material>();
materialDisplayNames = new Dictionary<Material, string>();
materialToggles = new Dictionary<Material, bool>();
filterMode = FilterMode.Point;
fixEdgesMode = FixEdgesModes.Regular;
}
public ModelViewerSettings(Shader objRenderShader, string rapidIconRootFolder, GameObject rootObject)
{
//---Initialise Icon---//
//Object Settings
objectPosition = Vector3.zero;
objectRotation = Vector3.zero;
objectScale = Vector3.one;
autoPosition = true;
//Hierarchy Settings
subObjectEnables = new Dictionary<string, bool>();
//Camera Settings
cameraPosition = new Vector3(1, Mathf.Sqrt(2), 1);
perspLastScale = 1;
cameraOrtho = true;
cameraFov = 60;
cameraSize = 5;
camerasScaleFactor = 1;
cameraTarget = Vector3.zero;
autoScale = true;
//Lighting Settings
ambientLightColour = Color.gray;
lightColour = Color.white;
lightDir = new Vector3(50, -30, 0);
lightIntensity = 1;
//Post-Processing Settings
postProcessingMaterials = new List<Material>();
materialDisplayNames = new Dictionary<Material, string>();
materialToggles = new Dictionary<Material, bool>();
filterMode = FilterMode.Point;
fixEdgesMode = FixEdgesModes.Regular;
// Material defaultRender = new Material(objRenderShader);
// postProcessingMaterials.Add(defaultRender);
// materialDisplayNames.Add(defaultRender, "Object Render");
// materialToggles.Add(defaultRender, true);
}
void SetSubObjectEnables(GameObject obj, int childIdx, string lastPath)
{
string path = lastPath + "/" + childIdx;
subObjectEnables.Add(path, true);
for (int i = 0; i < obj.transform.childCount; i++)
{
SetSubObjectEnables(obj.transform.GetChild(i).gameObject, i, path);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7ff80ea34f5f43069392dc52c7b49831
timeCreated: 1761415395

View File

@@ -0,0 +1,99 @@
using UnityEngine;
namespace NBF
{
public class ModelViewerUtils
{
public static ModelViewerSettings InitSetting(GameObject go, ModelViewerSettings settings)
{
if (settings.objectPosition.magnitude < 0.0001f)
settings.objectPosition = Vector3.zero;
//---Zero the GameObject euler angles if they're very small in magnitude---//
settings.objectRotation = go.transform.eulerAngles;
if (settings.objectRotation.magnitude < 0.0001f)
settings.objectRotation = Vector3.zero;
//---Set the object scale variable---//
settings.objectScale = go.transform.localScale;
//将默认对象位置设为使其位于图标中心的位置
Bounds bounds = GetObjectBounds(go);
settings.objectPosition = GetObjectAutoOffset(bounds);
// 将默认的相机设置调整为适合图标渲染中对象的呈现效果
float camAuto = GetCameraAuto(bounds);
settings.cameraSize = camAuto;
settings.cameraPosition = Vector3.one * camAuto;
return settings;
}
public static Bounds GetObjectBounds(GameObject go)
{
// 在将其位置归零之前先保存其位置信息
Vector3 prefabPos = go.transform.position;
go.transform.position = Vector3.zero;
// 创建一个边界对象,并将对象网格的边界进行封装。
MeshRenderer mr = go.GetComponent<MeshRenderer>();
Bounds bounds = new Bounds(Vector3.zero, 0.000001f * Vector3.one);
if (mr != null)
bounds.Encapsulate(mr.bounds);
else
{
SkinnedMeshRenderer smr = go.GetComponent<SkinnedMeshRenderer>();
if (smr != null)
bounds.Encapsulate(smr.bounds);
}
//同时将对象的子对象的范围也进行封装起来
EncapsulateChildBounds(go.transform, ref bounds);
//将预制物的位置重置为存储的值
go.transform.position = prefabPos;
return bounds;
}
public static Vector3 GetObjectAutoOffset(Bounds bounds)
{
//将偏移量应用到图标对象的位置上
return -bounds.center;
}
public static float GetCameraAuto(Bounds bounds)
{
//---Scale camera size and position so that the object fits in the render---//
Matrix4x4 trs = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0, 45, 0), 1.05f * Vector3.one);
Vector3 corner = new Vector3(bounds.extents.x, bounds.extents.y, bounds.extents.z);
corner = trs * corner;
Vector2 refB2 = new Vector2(0.74f, 0.53f);
Vector2 b2 = refB2 * corner.magnitude;
return b2.magnitude;
}
public static void EncapsulateChildBounds(Transform t, ref Bounds bounds)
{
// 遍历所有子对象,封装边界
MeshRenderer mr;
for (int i = 0; i < t.childCount; i++)
{
mr = t.GetChild(i).GetComponent<MeshRenderer>();
if (mr != null)
bounds.Encapsulate(mr.bounds);
else
{
SkinnedMeshRenderer smr = t.GetChild(i).GetComponent<SkinnedMeshRenderer>();
if (smr != null)
bounds.Encapsulate(smr.bounds);
}
EncapsulateChildBounds(t.GetChild(i), ref bounds);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 61157ac2e9594f58ae919731a4a5028c
timeCreated: 1761487911