166 lines
4.3 KiB
C#
166 lines
4.3 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using Unity.VisualScripting;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.Rendering;
|
||
|
|
//[ExecuteAlways]
|
||
|
|
public class RongMaoSkinMesh : MonoBehaviour
|
||
|
|
{
|
||
|
|
public int Count = 0;
|
||
|
|
//public Shader shader;
|
||
|
|
[Header("渲染目标")]
|
||
|
|
[SerializeField]
|
||
|
|
private Renderer Target;
|
||
|
|
public Shader BaseShader;
|
||
|
|
|
||
|
|
[Header("皮毛物理")]
|
||
|
|
public int LayerCount = 10;
|
||
|
|
public float FurLength = 0.5f;
|
||
|
|
public Vector3 FurFore;
|
||
|
|
public Texture2D Noise;
|
||
|
|
public Texture2D Noise2;
|
||
|
|
public Texture2D MainTex;//毛发颜色
|
||
|
|
public Texture2D Mask;//不产生毛发区域的灰度遮罩
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
[Header("皮毛渲染")]
|
||
|
|
//毛发染色
|
||
|
|
public Color FurColor=Color.white;
|
||
|
|
public Color ShadowColor=Color.white;
|
||
|
|
[Range(0,1)]public float ShadowStrength = 0.3f;
|
||
|
|
[Range(0.01f, 1)] public float R = 0.5f;
|
||
|
|
[Range(0, 3)] public float _LengthMut = 1;
|
||
|
|
[Header("是否使用GPU实例化")]
|
||
|
|
public bool isInStance = false;
|
||
|
|
|
||
|
|
|
||
|
|
private bool skinHasValue = false;
|
||
|
|
private Renderer target;
|
||
|
|
//创建毛发
|
||
|
|
private Mesh mesh;
|
||
|
|
private Material layerMat;
|
||
|
|
private SkinnedMeshRenderer skinnedMeshRenderer;
|
||
|
|
private MaterialPropertyBlock mpb;
|
||
|
|
|
||
|
|
private ComputeBuffer instanceBuffer;
|
||
|
|
private Matrix4x4[] instanceMatrices;
|
||
|
|
|
||
|
|
private bool isInit;
|
||
|
|
void OnEnable()
|
||
|
|
{
|
||
|
|
isInit = Init();
|
||
|
|
}
|
||
|
|
//更新毛发渲染
|
||
|
|
void LateUpdate()
|
||
|
|
{
|
||
|
|
//目标为空就不渲染
|
||
|
|
if(TargetChange()==false) return;
|
||
|
|
|
||
|
|
if(isInStance) UpDateInstance();
|
||
|
|
else UpDateMesh();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
bool TargetChange()
|
||
|
|
{
|
||
|
|
if (Target != target)
|
||
|
|
{
|
||
|
|
target = Target;
|
||
|
|
isInit = Init();
|
||
|
|
}
|
||
|
|
return isInit;
|
||
|
|
}
|
||
|
|
|
||
|
|
//初始化毛发,返回是否初始化成功
|
||
|
|
bool Init()
|
||
|
|
{
|
||
|
|
if(target.IsUnityNull()) return false;
|
||
|
|
CreateFur();
|
||
|
|
MeshInstancedData();
|
||
|
|
if (target.GetType() == typeof(MeshRenderer))
|
||
|
|
{
|
||
|
|
mesh=target.GetComponent<MeshFilter>().sharedMesh;
|
||
|
|
skinHasValue = false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
skinnedMeshRenderer = target.gameObject.GetComponent<SkinnedMeshRenderer>();
|
||
|
|
skinHasValue = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//初始化网格、材质、SkinnedMeshRenderer
|
||
|
|
void CreateFur()
|
||
|
|
{
|
||
|
|
mesh = new Mesh();
|
||
|
|
layerMat =new Material(BaseShader);
|
||
|
|
layerMat.SetTexture("_MainTex",MainTex);
|
||
|
|
layerMat.SetColor("_Color",FurColor);
|
||
|
|
layerMat.SetFloat("_FurLength",FurLength);
|
||
|
|
layerMat.SetTexture("_Noise",Noise);
|
||
|
|
layerMat.SetTexture("_Noise2",Noise2);
|
||
|
|
layerMat.SetTexture("_Mask",Mask);
|
||
|
|
layerMat.SetColor("_ShadowColor",ShadowColor);
|
||
|
|
layerMat.SetFloat("_R",R);
|
||
|
|
layerMat.SetFloat("_LayerCount",LayerCount);
|
||
|
|
layerMat.renderQueue = 3000;
|
||
|
|
|
||
|
|
mpb = new MaterialPropertyBlock();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void MeshInstancedData()
|
||
|
|
{
|
||
|
|
instanceMatrices = new Matrix4x4[LayerCount];
|
||
|
|
layerMat.enableInstancing = true;
|
||
|
|
// 随机生成实例的位置和旋转
|
||
|
|
for (int i = 0; i < LayerCount; i++)
|
||
|
|
{
|
||
|
|
Vector3 position = target.transform.position;
|
||
|
|
Quaternion rotation = target.transform.rotation;
|
||
|
|
Vector3 scale = Vector3.one;
|
||
|
|
|
||
|
|
instanceMatrices[i] = Matrix4x4.TRS(position, rotation, scale);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
//使用GPU实例化
|
||
|
|
void UpDateInstance()
|
||
|
|
{
|
||
|
|
|
||
|
|
if (skinHasValue)
|
||
|
|
{
|
||
|
|
skinnedMeshRenderer.BakeMesh(mesh);
|
||
|
|
}
|
||
|
|
|
||
|
|
layerMat.EnableKeyword("INSTANCE");
|
||
|
|
Graphics.DrawMeshInstanced(mesh,0,layerMat,instanceMatrices,LayerCount);
|
||
|
|
}
|
||
|
|
//未使用GPU实例化
|
||
|
|
void UpDateMesh()
|
||
|
|
{
|
||
|
|
if (skinHasValue)
|
||
|
|
{
|
||
|
|
skinnedMeshRenderer.BakeMesh(mesh);
|
||
|
|
}
|
||
|
|
|
||
|
|
layerMat.DisableKeyword("INSTANCE");
|
||
|
|
float furOffset = 1.0f / LayerCount;
|
||
|
|
for (int i = 0; i < LayerCount; i++)
|
||
|
|
{
|
||
|
|
mpb.SetFloat("_LayerOffset",i*furOffset);
|
||
|
|
Graphics.DrawMesh(mesh,target.transform.localToWorldMatrix,layerMat,0,Camera.main,0,mpb);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
}
|