157 lines
6.2 KiB
C#
157 lines
6.2 KiB
C#
|
using System.Collections.Generic;
|
|||
|
using Games.LogicObj;
|
|||
|
using Module.Log;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.Rendering;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 用于渲染透视效果的特殊渲染器
|
|||
|
/// </summary>
|
|||
|
public class XRayRenderer : MonoBehaviour
|
|||
|
{
|
|||
|
private static Material _xRayMaterial;
|
|||
|
private const string _xRayMaterialName = "PlayerXRay";
|
|||
|
|
|||
|
private List<MyTuple<SkinnedMeshRenderer, SkinnedMeshRenderer>> _skinnedMeshRendererList;
|
|||
|
private List<MeshRenderer> _meshRendererList;
|
|||
|
|
|||
|
// 注:不要修改为Start,需要保证在有子节点绑定前配置完成
|
|||
|
public void Init(List<RendererInfo> rendererInfos)
|
|||
|
{
|
|||
|
for (var i = 0; i < rendererInfos.Count; i++)
|
|||
|
{
|
|||
|
var cachedRenderer = rendererInfos[i].CachedRenderer;
|
|||
|
if (cachedRenderer == null ||
|
|||
|
cachedRenderer.sharedMaterial == null ||
|
|||
|
cachedRenderer.sharedMaterial.shader == null ||
|
|||
|
!cachedRenderer.sharedMaterial.shader.IsCharacterShader())
|
|||
|
continue;
|
|||
|
var meshRenderer = rendererInfos[i].CachedRenderer as MeshRenderer;
|
|||
|
if (meshRenderer == null)
|
|||
|
{
|
|||
|
var skinRenderer = rendererInfos[i].CachedRenderer as SkinnedMeshRenderer;
|
|||
|
if (skinRenderer != null)
|
|||
|
{
|
|||
|
if (_skinnedMeshRendererList == null)
|
|||
|
_skinnedMeshRendererList = new List<MyTuple<SkinnedMeshRenderer, SkinnedMeshRenderer>>();
|
|||
|
_skinnedMeshRendererList.Add(
|
|||
|
new MyTuple<SkinnedMeshRenderer, SkinnedMeshRenderer>(skinRenderer,
|
|||
|
CreateFromSkinnedRenderer(skinRenderer)));
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
var meshFilter = meshRenderer.GetComponent<MeshFilter>();
|
|||
|
if (meshFilter != null)
|
|||
|
{
|
|||
|
if (_meshRendererList == null)
|
|||
|
_meshRendererList = new List<MeshRenderer>();
|
|||
|
|
|||
|
_meshRendererList.Add(CreateFromMeshRenderer(meshRenderer, meshFilter));
|
|||
|
}
|
|||
|
#if UNITY_EDITOR
|
|||
|
else
|
|||
|
LogModule.ErrorLog(string.Format("MeshRenderer没有对应的MeshFilter,于物体{0}", meshRenderer.transform.GetHierarchyName()));
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void TrimXRaRenderer(Transform root)
|
|||
|
{
|
|||
|
if (root != null)
|
|||
|
{
|
|||
|
if (_skinnedMeshRendererList != null)
|
|||
|
{
|
|||
|
for (var i = _skinnedMeshRendererList.Count - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
if (_skinnedMeshRendererList[i].first == null ||
|
|||
|
_skinnedMeshRendererList[i].first.transform.IsChildOf(root))
|
|||
|
_skinnedMeshRendererList.RemoveAt(i);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (_meshRendererList != null)
|
|||
|
{
|
|||
|
for (var i = _meshRendererList.Count - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
if (_meshRendererList[i] == null || _meshRendererList[i].transform.IsChildOf(root))
|
|||
|
_meshRendererList.RemoveAt(i);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void ResetBones()
|
|||
|
{
|
|||
|
if (_skinnedMeshRendererList != null)
|
|||
|
for (var i = _skinnedMeshRendererList.Count - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
SetBones(_skinnedMeshRendererList[i].first, _skinnedMeshRendererList[i].second);
|
|||
|
_skinnedMeshRendererList[i].second.gameObject.SetActive(true);
|
|||
|
}
|
|||
|
if (_meshRendererList != null)
|
|||
|
for (var i = 0; i < _meshRendererList.Count; i++)
|
|||
|
_meshRendererList[i].gameObject.SetActive(true);
|
|||
|
}
|
|||
|
|
|||
|
public void Hide()
|
|||
|
{
|
|||
|
if (_skinnedMeshRendererList != null)
|
|||
|
for (var i = 0; i < _skinnedMeshRendererList.Count; i++)
|
|||
|
_skinnedMeshRendererList[i].second.gameObject.SetActive(false);
|
|||
|
if (_meshRendererList != null)
|
|||
|
for (var i = 0; i < _meshRendererList.Count; i++)
|
|||
|
_meshRendererList[i].gameObject.SetActive(false);
|
|||
|
}
|
|||
|
|
|||
|
private static MeshRenderer CreateFromMeshRenderer(MeshRenderer sourceRenderer, MeshFilter sourceFilter)
|
|||
|
{
|
|||
|
// 注:可能有些物体会拥有初始动画
|
|||
|
var xRayObject = BuildXRayObject(sourceRenderer);
|
|||
|
var targetFilter = xRayObject.AddComponent<MeshFilter>();
|
|||
|
var targetRenderer = xRayObject.AddComponent<MeshRenderer>();
|
|||
|
targetFilter.sharedMesh = sourceFilter.sharedMesh;
|
|||
|
SetRendererParameters(sourceRenderer, targetRenderer);
|
|||
|
return targetRenderer;
|
|||
|
}
|
|||
|
|
|||
|
private static SkinnedMeshRenderer CreateFromSkinnedRenderer(SkinnedMeshRenderer sourceRenderer)
|
|||
|
{
|
|||
|
var xRayObject = BuildXRayObject(sourceRenderer);
|
|||
|
var targetRenderer = xRayObject.AddComponent<SkinnedMeshRenderer>();
|
|||
|
SetBones(sourceRenderer, targetRenderer);
|
|||
|
targetRenderer.sharedMesh = sourceRenderer.sharedMesh;
|
|||
|
SetRendererParameters(sourceRenderer, targetRenderer);
|
|||
|
return targetRenderer;
|
|||
|
}
|
|||
|
|
|||
|
private static void SetBones(SkinnedMeshRenderer sourceRenderer, SkinnedMeshRenderer targetRenderer)
|
|||
|
{
|
|||
|
targetRenderer.rootBone = sourceRenderer.rootBone;
|
|||
|
targetRenderer.bones = sourceRenderer.bones;
|
|||
|
}
|
|||
|
|
|||
|
private static GameObject BuildXRayObject(Component root)
|
|||
|
{
|
|||
|
var xRayObject = new GameObject("XRayObject");
|
|||
|
xRayObject.transform.SetParent(root.transform);
|
|||
|
xRayObject.transform.localPosition = Vector3.zero;
|
|||
|
xRayObject.transform.localRotation = Quaternion.identity;
|
|||
|
xRayObject.transform.localScale = Vector3.one;
|
|||
|
return xRayObject;
|
|||
|
}
|
|||
|
|
|||
|
private static void SetRendererParameters(Renderer source, Renderer target)
|
|||
|
{
|
|||
|
if (_xRayMaterial == null)
|
|||
|
_xRayMaterial = CommonUtility.LoadSharedMaterial(_xRayMaterialName);
|
|||
|
target.shadowCastingMode = ShadowCastingMode.Off;
|
|||
|
target.receiveShadows = false;
|
|||
|
var materials = new Material[source.sharedMaterials.Length];
|
|||
|
for (var i = 0; i < materials.Length; i++)
|
|||
|
materials[i] = _xRayMaterial;
|
|||
|
target.sharedMaterials = materials;
|
|||
|
target.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
|
|||
|
}
|
|||
|
}
|