You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
5.1 KiB
C#

using System;
using System.Linq;
using System.Threading;
using UnityEngine;
using UnityEngine.Rendering;
namespace FluffyGroomingTool {
[Serializable]
public class ClumpModifierLayer : ICloneable {
[SerializeField] public HairStrand[] clumps = new HairStrand[0];
public AnimationCurve attractionCurve;
public ComputeBuffer clumpsBuffer;
public ComputeBuffer clumpsPositionBuffer;
public ComputeBuffer clumpAttractionBuffer;
public void recreateClumpBuffer() {
if (clumps.Length > 0) {
clumpsBuffer?.Dispose();
clumpsBuffer = new ComputeBuffer(clumps.Length, HairStrandStruct.size());
var clumpsStructs = clumps.ToList().Select(it => it.convertToStruct()).ToArray();
clumpsBuffer.SetData(clumpsStructs);
disposePositionAndAttractionBuffers();
}
}
private void disposePositionAndAttractionBuffers() {
clumpsPositionBuffer?.Dispose();
clumpsPositionBuffer = null;
clumpAttractionBuffer?.Dispose();
clumpAttractionBuffer = null;
}
public void dispatchParentClumpKernel(ComputeShader cs, int kernel, FurRenderer renderer, CardMeshProperties cardMeshProperties) {
if (clumpsBuffer != null) {
var clumpYCoordinates = cardMeshProperties.getCardMeshVerticesY();
var clumpsPositionBufferCount = clumpYCoordinates * clumpsBuffer.count;
if (clumpsPositionBuffer == null)
clumpsPositionBuffer = new ComputeBuffer(clumpsPositionBufferCount, sizeof(float) * 4, ComputeBufferType.Default);
cs.DisableKeyword("IS_CHILD_CLUMP");
cs.SetFloat("clumpPointsCount", clumpsPositionBufferCount);
cs.SetBuffer(kernel, "sourceMesh", renderer.meshBaker.bakedMesh);
cs.SetBuffer(kernel, "clumpPointsPosition", clumpsPositionBuffer);
cs.SetBuffer(kernel, "clumpsBuffer", clumpsBuffer);
cs.SetInt("clumpYCoordinates", clumpYCoordinates);
cs.Dispatch(kernel, clumpsPositionBufferCount.toCsGroups(), 1, 1);
}
}
public void dispatchChildClumpKernel(ClumpModifierLayer parentClumpModifier, ComputeShader cs, int kernel, FurRenderer renderer,
CardMeshProperties cardMeshProperties) {
if (clumpsBuffer != null) {
cs.EnableKeyword("IS_CHILD_CLUMP");
var clumpYCoordinates = cardMeshProperties.getCardMeshVerticesY();
var clumpsPositionBufferCount = clumpYCoordinates * clumpsBuffer.count;
if (clumpsPositionBuffer == null)
clumpsPositionBuffer = new ComputeBuffer(clumpsPositionBufferCount, sizeof(float) * 4, ComputeBufferType.Default);
cs.SetBool("isChildClumpKernel", true);
cs.SetInt("clumpYCoordinates", clumpYCoordinates);
cs.SetFloat("clumpPointsCount", clumpsPositionBufferCount);
cs.SetBuffer(kernel, "clumpPointsPosition", clumpsPositionBuffer);
cs.SetBuffer(kernel, "parentClumpPointsPosition", parentClumpModifier.clumpsPositionBuffer);
cs.SetBuffer(kernel, "clumpsBuffer", clumpsBuffer);
cs.SetBuffer(kernel, "clumpAttractionCurve", parentClumpModifier.clumpAttractionBuffer);
cs.Dispatch(kernel, clumpsPositionBufferCount.toCsGroups(), 1, 1);
}
}
public void dispose() {
disposePositionAndAttractionBuffers();
clumpsBuffer?.Dispose();
clumpsBuffer = null;
}
public void createClumpAttractionBuffer(int attractionPointsCount) {
clumpAttractionBuffer = new ComputeBuffer(attractionPointsCount, sizeof(float));
}
public void updateClumpAttractionBuffer() {
if (clumpAttractionBuffer != null) {
var count = clumpAttractionBuffer.count;
var data = new float[count];
for (int i = 0; i < count; i++) {
data[i] = attractionCurve.Evaluate((float) i / count);
}
clumpAttractionBuffer.SetData(data);
}
}
public void copyFromComputeBufferToNativeObject() {
if (clumpsBuffer != null) AsyncGPUReadback.Request(clumpsBuffer, OnCompleteReadback);
}
void OnCompleteReadback(AsyncGPUReadbackRequest request) {
if (request.hasError) {
Debug.Log("GPU readback error detected for Clumps in FurContainer.");
return;
}
var hairStrandStructs = request.ToPersistentArray<HairStrandStruct>();
new Thread(() => {
clumps = hairStrandStructs.Select(it => it.convertToObject()).ToArray();
hairStrandStructs.Dispose();
}).Start();
}
void convertNativeArrayToStructs() { }
public object Clone() {
return new ClumpModifierLayer {
clumps = clumps,
attractionCurve = new AnimationCurve(attractionCurve.keys)
};
}
}
}