版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27124771/article/details/83539980
为什么要用计算着色器呢? 因为人脸表情基模型顶点数实在是太多了,而且有不止一个模型,动画越精细,表情基模型越多,这个时候仅仅用CPU计算显然是不够的,所以就开始上GPU了,并行计算。
直接上计算着色器的代码:
1、ComputeShader.compute
#pragma kernel Cul
RWStructuredBuffer<float3> vertBuffer;
StructuredBuffer<float3> blendshapeBuffer;
StructuredBuffer<float3> naturalBuffer;
float weight;//表情基权重
[numthreads(32,32,1)]
void Cul(uint3 id : SV_DispatchThreadID) {
int index = id.x * 32 * 4 + id.y;
vertBuffer[index] = vertBuffer[index] + (blendshapeBuffer[index] - naturalBuffer[index]) * weight;
}
2、ComputeShaderCS.cs
[RequireComponent(typeof(MeshFilter))]
public class ComputeShaderCS : MonoBehaviour {
//表情基的Mesh网格 0为natural模型
public Mesh[] meshs;
//每个表情基的权重值数组(限制在0-1)
[Range(0,1)]
public float[] weights;
//计算着色器
public ComputeShader shader;
ComputeBuffer vertBuffer; //顶点缓冲
ComputeBuffer blendshapeBuffer; //表情基模型缓冲
ComputeBuffer naturalBuffer; //natural模型缓冲
//模型网格信息
Mesh mesh;
private void Start() {
//获取模型的网格信息
mesh = GetComponent<MeshFilter>().mesh;
//分配缓冲空间(每个float占4个字节,一个Vector3包括3个float,所占大小为4*3)
vertBuffer = new ComputeBuffer(meshs[0].vertices.Length, 4 * 3);
blendshapeBuffer = new ComputeBuffer(meshs[0].vertices.Length, 4 * 3);
naturalBuffer = new ComputeBuffer(meshs[0].vertices.Length, 4 * 3);
}
private void Update() {
//不必每一帧执行,此处为便于测试
RunShader();
}
//执行计算着色器
void RunShader() {
int kernel = shader.FindKernel("Cul");
Vector3[] vertices = new Vector3[meshs[0].vertices.Length];
//初始化缓冲
vertBuffer.SetData(meshs[0].vertices);
naturalBuffer.SetData(meshs[0].vertices);
//填充缓冲
shader.SetBuffer(kernel, "vertBuffer", vertBuffer);
shader.SetBuffer(kernel, "naturalBuffer", naturalBuffer);
//根据权重值与表情基计算新的顶点位置
for (int w = 1; w < weights.Length; w++) {
if (weights[w] <= 0) continue;
//初始化缓冲
blendshapeBuffer.SetData(meshs[w].vertices);
//填充缓冲
shader.SetBuffer(kernel, "blendshapeBuffer", blendshapeBuffer);
//设置权重
shader.SetFloat("weight", weights[w]);
//执行Compute Shader
shader.Dispatch(kernel, 4, 4, 1);
}
//获取计算结果
vertBuffer.GetData(vertices);
//更改网格结构
mesh.vertices = vertices;
}
void OnDestroy() {
if (vertBuffer != null) vertBuffer.Release();
if (blendshapeBuffer != null) blendshapeBuffer.Release();
if (naturalBuffer != null) naturalBuffer.Release();
}
}