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.

150 lines
5.2 KiB
HLSL

int verletNodesCount; //
float _Decay; //
float3 _Gravity; //
#include "SDFColliderInclude.hlsl"
RWStructuredBuffer<VerletNode> verletNodes;
uniform float shapeConstraintRoot;
uniform float shapeConstraintTip;
uniform float stepSize;
uniform uint nearestPow;
uniform uint strandPointsCount;
uniform int solverIterations;
uniform uint layerVertexStartIndex;
uniform float3 worldSpaceCameraPos;
uniform uint numberOfFixedNodesInStrand;
float3 calculateTangent(float3 currentRestPos, float3 prevRestPosition, float3 nextRestPos, const bool isNextNodeFixed)
{
float3 tangent;
if (!isNextNodeFixed)
{
tangent = normalize(nextRestPos - currentRestPos);
}
else
{
tangent = normalize(currentRestPos - prevRestPosition);
}
return tangent;
}
bool calculateIndicesAndDiscard(uint3 id, out uint index, out uint localPointIndex, out uint hairStrandIndex)
{
uint fakeIdx = id.x;
hairStrandIndex = floor(fakeIdx / nearestPow);
localPointIndex = fakeIdx - hairStrandIndex * nearestPow;
index = layerVertexStartIndex + hairStrandIndex * strandPointsCount + localPointIndex;
uint vnc = verletNodesCount;
if (localPointIndex >= strandPointsCount || index >= vnc) return true;
return false;
}
float3 slerp(float3 start, float3 end, float percent)
{
float dotP = dot(start, end);
dotP = clamp(dotP, -1.0, 1.0);
const float theta = acos(dotP) * percent;
const float3 relativeVec = normalize(end - start * dotP);
return theta == 0 ? start : start * cos(theta) + relativeVec * sin(theta);
}
float3 bendConstraintInv(
VerletNode n,
const VerletNode nNext,
const float intensity
)
{
float3 perfectMatch = nNext.position + (n.tangent - n.rotationDiffFromPrevNode2) * distance(n.position, nNext.position);
return lerp(n.position, perfectMatch, stepSize * intensity* deltaTime);
}
float3 bendConstraint(
VerletNode n,
const VerletNode nPrev,
const float intensity
)
{
float3 perfectMatch = nPrev.position + (nPrev.tangent - n.rotationDiffFromPrevNode) * distance(n.position, nPrev.position);
return lerp(n.position, perfectMatch, stepSize * intensity* deltaTime);
}
float3 compute_delta(float3 a, float3 b, float segmentLengt)
{
float3 direction = normalize(a - b);
const float mDist = length(a - b) - segmentLengt;
return direction * mDist * 0.5;
}
void velocityGravityAndCollision(float3 currentRestPosition, bool isFixedNode, float currentVertMoveAbility, float pinnedAmount, int index)
{
VerletNode currentNode = verletNodes[index];
//Got teleported
if (distance(currentNode.position, currentNode.prevPosition) > 1)
{
currentNode.position = currentRestPosition;
currentNode.prevPosition = currentRestPosition;
}
//Gravity
currentNode.position += _Gravity * deltaTime * !isFixedNode;
//Velocity
float3 v = currentNode.position - currentNode.prevPosition;
float3 next = currentNode.position + v * _Decay;
currentNode.prevPosition = currentNode.position;
currentNode.position = next;
currentNode.position = applyWind(currentNode.position, currentRestPosition);
//Sphere and capsule colliders
#if defined(HAS_COLLIDERS)
currentNode.position = applyColliders(currentNode.position);
#endif
#if defined(COLLIDE_WITH_SOURCE_MESH)
int didSDFCollide=0;
#if defined(USE_FORWARD_COLLISION)
CollideHairVerticesWithSdf_forward(didSDFCollide, currentNode.position, currentVertMoveAbility);
//if(didSDFCollide == 1) currentNode.prevPosition = currentNode.position;//Could we use this for friction?
#else
collideWithSDF(didSDFCollide, currentNode.position, currentVertMoveAbility);
#endif
//if(didSDFCollide == 1) currentNode.prevPosition = currentNode.position;
#endif
currentNode.position = lerp(currentNode.position, currentRestPosition, pinnedAmount * deltaTime);
verletNodes[index] = currentNode;
GroupMemoryBarrierWithGroupSync();
}
void constraints(int index, float3 restPos, float3 restPosNext, float3 restPosPrev, bool isNextNodeFixed, float shapeConstraintIntensity)
{
const bool isNotLastNode = (int)index < verletNodesCount - 1;
for (int i = 0; i < solverIterations; i++)
{
VerletNode currentNode = verletNodes[index];
if (isNotLastNode)
{
if (!isNextNodeFixed)
{
VerletNode nNext = verletNodes[index + 1];
float nodeLength = distance(restPos, restPosNext);
currentNode.position = bendConstraintInv(currentNode, nNext,shapeConstraintIntensity);
currentNode.position -= compute_delta(currentNode.position, nNext.position, nodeLength);
}
}
GroupMemoryBarrierWithGroupSync();
VerletNode nPrev = verletNodes[index - 1];
const float nodeLengthPrev = distance(restPosPrev, restPos);
currentNode.position = bendConstraint(currentNode, nPrev,shapeConstraintIntensity);
GroupMemoryBarrierWithGroupSync();
currentNode.position += compute_delta(nPrev.position, currentNode.position, nodeLengthPrev);
verletNodes[index] = currentNode;
GroupMemoryBarrierWithGroupSync();
}
GroupMemoryBarrierWithGroupSync();
}