海飞丝头发学习笔记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)
{
这里推测sizeY是每一个小段里面继续细分的段数
那么x*SizeY就是更小的段的下标,t*sizeY就是一小段里面的下标余数,y-1 y y+1就构成了最近的3个控制点。localT是更小段的余数构造出的随机曲线
	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;
}



[numthreads(THREADS,1,1)]
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
{
这里面存着头发的网格信息,包括meshfilter,顶点组,顶点,颜色
    [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

public HairPhysicsWorld(HairDataFacade data)
    {
        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;
    }

 

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值