# 海飞丝头发学习笔记2

https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter23.html

GpuGem2里有讲流程

贝塞尔曲线知乎文章：
https://zhuanlan.zhihu.com/p/29460544

function Bezier(2,t,w[]):

t2 = t * t

mt = 1-t

mt2 = mt * mt

return w[0]*mt2 + w[1]*2*mt*t + w[2]*t2

float3 GetBezierPoint(float3 p0, float3 p1, float3 p2, float t)
{
float invT = 1 - t;
return invT*invT*p0 + 2 * invT*t*p1 + t*t*p2;
}

float3 GetSplinePoint(int x, float t, uint sizeY)
{

int sizeYm1 = sizeY - 1;
int y = (uint)(t*sizeY);
half tStep = 1.0f / sizeY;
half localT = (t % tStep) * sizeY;

int startI = x*sizeY;

int y0 = max(0, y - 1);
int y1 = min(y, sizeYm1);
int y2 = min(y + 1, sizeYm1);

float3 p0 = particles[startI + y0].position;
float3 p1 = particles[startI + y1].position;
float3 p2 = particles[startI + y2].position;

float3 cPoint1 = (p0 + p1)*0.5f;
float3 cPoint2 = (p1 + p2)*0.5f;

return GetBezierPoint(cPoint1, p1, cPoint2, localT);
}

RenderParticle GetSplineBodyData(int x, half t, uint sizeY)//refactor copy/paste
{
int sizeYm1 = sizeY - 1;
int y = (int)(t*sizeY);
half tStep = 1.0f / sizeY;
half localT = (t % tStep) * sizeY;

int startI = x*sizeY;

int y1 = min(y, sizeYm1);
int y2 = min(y + 1, sizeYm1);

RenderParticle b1 = renderParticles[startI + y1];
RenderParticle b2 = renderParticles[startI + y2];

RenderParticle b;
b.color = lerp(b1.color, b2.color, localT);
b.interpolation = lerp(b1.interpolation, b2.interpolation, localT);
b.wavinessScale = lerp(b1.wavinessScale, b2.wavinessScale, localT);
b.wavinessFrequency = lerp(b1.wavinessFrequency, b2.wavinessFrequency, localT);

return b;
}

void CSTesselate (uint3 id : SV_DispatchThreadID)
{
//y是整个段的余数，x是第几个段，t代表这个段里面占的百分比，tessStep就是每一小段的长度

uint y = id.x % tessSegments;
uint x = id.x / tessSegments;

float t = y / (float)tessSegments;
float tessStep = 1.0/tessSegments;

float3 tessPosition =  GetSplinePoint(x, saturate(t), segments);
//float3 tessPosition0 =  particles[x*segments].position;
//float3 tessPosition1 =  particles[x*segments + segments - 1].position;
//float3 tessBinormal = normalize(tessPosition1 - tessPosition0);
//float3 tessTangent = cross(tessBinormal, wavinessAxis);
//float3 axis = cross()

RenderParticle renderParticle = GetSplineBodyData(x, saturate(t), segments);

float3 curve = CurveDirrection(normalize(wavinessAxis), half2(t, x), renderParticle.wavinessScale, renderParticle.wavinessFrequency);

TessRenderParticle tessParticle;

tessParticle.position = tessPosition + curve;
tessParticle.tangent = float3(0,0,0);
tessParticle.color = renderParticle.color;
tessParticle.interpolation = renderParticle.interpolation;
tessRenderParticles[id.x] = tessParticle;

AllMemoryBarrierWithGroupSync();

int sign = y == 0 ? -1 : 1;
tessRenderParticles[id.x].tangent = normalize(tessParticle.position - tessRenderParticles[id.x - sign].position)*sign;
}

public class HairGroupsProvider
{

[SerializeField] public List<MeshFilter> HairFilters = new List<MeshFilter>();

[SerializeField] public List<List<Vector3>> VerticesGroups;
[SerializeField] public List<Vector3> Vertices;

[SerializeField] public List<List<Color>> ColorsGroups;
[SerializeField] public List<Color> Colors;

public void Process(Matrix4x4 worldToObject)
{
VerticesGroups = InitVerticesGroups(worldToObject);
Vertices = InitVertices();
ColorsGroups = InitColorGroups();
Colors = InitColors();
}

private List<List<Vector3>> InitVerticesGroups(Matrix4x4 worldToObject)
{
return HairFilters.Select(filter => MeshUtils.GetVerticesInSpace(filter.sharedMesh, filter.transform.localToWorldMatrix, worldToObject)).ToList();
}

private List<Vector3> InitVertices()
{
return VerticesGroups.SelectMany(verticesGroup => verticesGroup).ToList();
}

private List<List<Color>> InitColorGroups()
{
return HairFilters.Select(filter => filter.sharedMesh.colors.ToList()).ToList();
}

private List<Color> InitColors()
{
return ColorsGroups.SelectMany(colorsGroup => colorsGroup).ToList();
}

public bool Validate(bool log)
{
if (Validator.TestList(HairFilters))
return true;

if (log)
Debug.LogError("Hair list is empty or contains empty elements ");

return false;
}
}

[Serializable]
public class MeshProvider : IMeshProvider
{
public ScalpMeshType Type = ScalpMeshType.Static;

[SerializeField] public SkinnedMeshProvider SkinnedProvider = new SkinnedMeshProvider();
[SerializeField] public StaticMeshProvider StaticProvider = new StaticMeshProvider();

public bool Validate(bool log)
{
return GetCurrentProvider().Validate(log);
}

public void Dispatch()
{
GetCurrentProvider().Dispatch();
}

public void Dispose()
{
GetCurrentProvider().Dispose();
}

private IMeshProvider GetCurrentProvider()
{
if (Type == ScalpMeshType.Static)
return StaticProvider;

return SkinnedProvider;
}

public Matrix4x4 ToWorldMatrix
{
get { return GetCurrentProvider().ToWorldMatrix; }
}

public GpuBuffer<Matrix4x4> ToWorldMatricesBuffer
{
get { return GetCurrentProvider().ToWorldMatricesBuffer; }
}

public Mesh Mesh
{
get { return GetCurrentProvider().Mesh; }
}
}



这里有个非常巧妙的设计，所有的数据大小都设置完毕了，然后传递给HairPhysicWorld这个类存起来，然后Bind一下，Bind的功能就是将所有的自己的属性，都赋值给所有的pass

{
this.data = data;

T = new GpuValue<float>();
Step = new GpuValue<float>();
Gravity = new GpuValue<Vector3>();
InvDrag = new GpuValue<float>();
Wind = new GpuValue<Vector3>();
Segments = new GpuValue<int>();
TessSegments = new GpuValue<int>();
WavinessAxis = new GpuValue<Vector3>();

InitData();
InitBuffers();
InitPasses();

Bind();
}

private void InitData()
{
Step.Value = 1f / data.Iterations;
Gravity.Value = data.Gravity;
InvDrag.Value = data.InvDrag;
Wind.Value = data.Wind;
Segments.Value = (int)data.Size.y;
TessSegments.Value = (int)data.TessFactor.y;
WavinessAxis.Value = data.WorldWavinessAxis;
}

private void InitBuffers()
{
Particles = data.Particles;
Transforms = data.MatricesBuffer;
OldTransforms = new GpuBuffer<Matrix4x4>(Transforms.Count, sizeof(float) * 16);
PointJoints = data.PointJoints;
StaticSpheres = data.StaticSpheres;
RenderParticles = data.RenderParticles;
TessRenderParticles = data.TessRenderParticles;
OutParticles = data.OutParticles;
OutParticlesMap = data.OutParticlesMap;
OldStaticSpheres = data.OldStaticSpheres;
}

03-23 918

03-19 167

04-09 5375

09-29 2059

09-06 1130

12-09 2万+

04-21 61

02-13 5916

04-17 53

10-26 3120

#### 京东AI平台是干什么的？还行，有点特色

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。