NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/Scene/SceneObject.cs

232 lines
5.8 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Sirenix.OdinInspector;
using UnityEngine.Serialization;
using Object = System.Object;
public enum ESceneObjectType
{
None = 0,
Tree = 1, //树
Buildings = 2, //建筑物
}
/// <summary>
/// 场景中对象,可以方便地执行一些渲染上的效果,如半透,面片渲染等
/// </summary>
public class SceneObject : MonoBehaviour
{
#region Fields
[SerializeField]
private bool _transparent;
[SerializeField]
private bool _useSurface;
[SerializeField]
public SceneObjectRenderInfo renderInfo;
[SerializeField]
public ESceneObjectType sceneObjectType;
private bool Valid => renderInfo != null;
private SceneSurfaceData _surfaceData;
public SceneSurfaceData SurfaceData
{
get
{
if (_surfaceData == null || !_surfaceData.valid)
{
NLDSceneManager sceneManager;
if (Application.isPlaying)
{
sceneManager = NLDSceneManager.instance;
}
else
{
sceneManager = FindObjectOfType<NLDSceneManager>();
}
if (sceneManager != null)
{
sceneManager.Refresh();
_surfaceData = sceneManager.GetSurfaceData(renderInfo);
}
}
return _surfaceData;
}
}
public bool SupportSurface => SurfaceData != null && SurfaceData.IsGameObjectValid(gameObject);
private Vector3 _originMeshScale;
private Vector3 _originMeshPosition;
private Quaternion _originMeshRotation;
#endregion
#region API
public bool Transparent
{
get => _transparent;
set
{
if (_transparent != value && Valid)
{
_transparent = value;
RefreshTransparent();
}
}
}
public bool UseSurface
{
get => _useSurface;
set
{
if (_useSurface != value)
{
if (value && !SupportSurface)
{
return;
}
_useSurface = value;
RefreshSurface();
}
}
}
#endregion
#region MainLife
private void Start()
{
}
#endregion
private void SaveSurfaceTransformValues(Transform meshTrans)
{
_originMeshScale = meshTrans.localScale;
_originMeshPosition = meshTrans.position;
_originMeshRotation = meshTrans.rotation;
}
private void RevertSurfaceTransformValues(Transform surfaceTrans)
{
surfaceTrans.localScale = _originMeshScale;
surfaceTrans.position = _originMeshPosition;
surfaceTrans.rotation = _originMeshRotation;
}
private void RefreshAllMaterials(List<Material> mats)
{
if (mats == null || mats.Count == 0)
return;
var meshrenderers = GetComponentsInChildren<MeshRenderer>();
int matIndex = 0;
List<Material> matsToSet = new();
foreach (var meshrenderer in meshrenderers)
{
matsToSet.Clear();
var msf = meshrenderer.GetComponent<MeshFilter>();
var mesh = msf.sharedMesh;
for (int i = 0; i < mesh.subMeshCount; i++)
{
Material matToSet = matIndex >= mats.Count ? null : mats[matIndex];
matsToSet.Add(matToSet);
matIndex++;
}
meshrenderer.SetSharedMaterials(matsToSet);
}
}
private void RefreshAllMeshes(List<Mesh> meshes)
{
if (meshes == null || meshes.Count == 0)
return;
var msfs = GetComponentsInChildren<MeshFilter>();
int meshIndex = 0;
foreach (var msf in msfs)
{
Mesh mesh = null;
if (meshIndex < meshes.Count)
mesh = meshes[meshIndex];
msf.sharedMesh = mesh;
meshIndex++;
}
}
private void RefreshTransparent()
{
if (!_useSurface)
{
RefreshAllMaterials(_transparent ? renderInfo.transparentMaterial : renderInfo.opaqueMaterial);
}
else
{
}
}
private void RefreshSurface()
{
if (_useSurface)
{
ChangeGameObjectToSurface();
}
else
{
ChangeGameObjectToReal();
}
}
private async void ChangeGameObjectToSurface()
{
var mat = await SurfaceData.GetMaterial();
if (mat == null)
{
_useSurface = false;
return;
}
var msr = gameObject.GetComponentInChildren<MeshRenderer>();
var msf = msr.GetComponent<MeshFilter>();
if (msr == null)
return;
var meshTrans = msr.transform;
SaveSurfaceTransformValues(meshTrans);
msf.sharedMesh = await SceneSurfaceData.GetSurfaceMesh();
RefreshAllMaterials(new List<Material>() { mat });
//必须是统一缩放
var rootScale = transform.localScale.x;
meshTrans.position += SurfaceData.cachedOffset * rootScale;
if (meshTrans == transform)
meshTrans.localScale = SurfaceData.cachedScale * rootScale;
else
meshTrans.localScale = SurfaceData.cachedScale;
meshTrans.eulerAngles = SurfaceData.cachedRotation;
}
private void ChangeGameObjectToReal()
{
var msr = gameObject.GetComponentInChildren<MeshRenderer>();
if (msr == null)
return;
var meshTrans = msr.transform;
RefreshAllMeshes(renderInfo.meshes);
RefreshTransparent();
RevertSurfaceTransformValues(meshTrans);
}
}