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.

201 lines
5.5 KiB
HLSL

#define SKIN_WIDTH 1.01
#define MAX_EASED_MOVE_DISTANCE 1
#define WIND_SENSITIVITY_DIVIDER 40
#include "CommonConstants.cginc"
struct MeshProperties
{
float3 sourceVertex;
float3 sourceNormal;
float4 sourceTangent;
};
struct MeshFullProperties
{
float3 sourceVertex;
float3 sourceNormal;
float4 sourceTangent;
float4 sourceColor;
float2 sourceUV;
};
uniform RWByteAddressBuffer furMeshBuffer;
uniform uint furMeshBufferStride;
float sourceMeshNormalToStrandNormalPercent;
void writeVector3(uint index, uint offset, float3 value)
{
furMeshBuffer.Store3(index + offset, asuint(value));
}
void writeVector4(uint index, uint offset, float4 value)
{
furMeshBuffer.Store4(index + offset, asuint(value));
}
void writeVector2(uint index, uint offset, float2 value)
{
furMeshBuffer.Store2(index + offset, asuint(value));
}
float3 loadSourceVertex(uint index)
{
return asfloat(furMeshBuffer.Load3(index));
}
float rand(float n)
{
return frac(sin(dot(float2(n, n * 2), float2(12.9898, 4.1414))) * 43758.5453) - 0.5;
}
struct HairStrandStruct
{
float4 bend;
float4x4 scaleMatrix;
float4x4 rootAndOrientationMatrix;
float2 uv;
float2 uvOffset;
float3 triangles;
float3 barycentricCoordinates;
float windContribution;
int clumpIndices;
float clumpMask;
float4 twist;
float4 overrideColor;
};
struct ColliderStruct
{
float3 position;
float3 position2;
float radius;
};
struct VerletNode
{
float3 position;
float3 prevPosition;
bool isFixed;
float3 tangent;
float3 rotationDiffFromPrevNode;
float3 rotationDiffFromPrevNode2;
};
struct VerletRestNode
{
float3 position;
float3 worldSourceMeshNormal;
float vertMoveAbility;
float pinnedAmount;
};
bool isFixed(VerletNode node)
{
return node.isFixed;
}
uniform float objectGlobalScale;
uniform StructuredBuffer<HairStrandStruct> hairStrandsBuffer;
uniform float4x4 objectRotationMatrix;
float4x4 localToWorldMatrix;
float deltaTime;
//WIND
float time;
Texture2D<float4> WindDistortionMap;
SamplerState sampler_WindDistortionMap;
float WindGust;
float WindStrength;
float3 WindDirection;
//END WIND
//COLLISION
int CollidersCount;
RWStructuredBuffer<ColliderStruct> ColliderBuffer;
//END COLLISION
float3 Step(float3 current, float omega)
{
float ex = saturate(exp(-omega * deltaTime));
return lerp(float3(0, 0, 0), current, ex);
}
float3 applyWind(float3 desiredPosition, float3 currentPosition)
{
const float3 worldPos = currentPosition;
float2 uv = worldPos.xz + float2(WindGust, WindGust) * time;
float2 windSample = WindDistortionMap.SampleLevel(sampler_WindDistortionMap, uv, 0).xy;
float ws = WindStrength + (sin(time + worldPos.y * 4) + cos(time * 5 + worldPos.y * 4)) / 4 * WindStrength;
desiredPosition += float3((windSample.x - 0.5) * 2, 0, (windSample.y - 0.5) * 2) / WIND_SENSITIVITY_DIVIDER * ws + WindDirection.xyz * ws / 100;
return desiredPosition;
}
float sqrMag(float3 input)
{
return input.x * input.x + input.y * input.y + input.z * input.z;
}
float3 sphereCollide(ColliderStruct collider, float3 desiredPosition)
{
//Sphere collider
float dist = distance(desiredPosition, collider.position);
dist = collider.radius * SKIN_WIDTH - clamp(0.0, collider.radius * SKIN_WIDTH, dist);
desiredPosition += normalize(desiredPosition - collider.position) * dist;
return desiredPosition;
}
float3 capsuleMiddleCollide(ColliderStruct collider, float3 desiredPosition)
{
const float3 top = collider.position;
const float3 bottom = collider.position2;
const float3 position = desiredPosition;
const float3 bottomMinusTop = bottom - top;
const float3 topMinusBottom = -bottomMinusTop;
const float3 posMinusTop = position - top;
const float3 posMinusBottom = position - bottom;
const float dot_Top = dot(bottomMinusTop, posMinusTop);
const float dot_Bottom = dot(topMinusBottom, posMinusBottom);
if (dot_Top >= 0.0f && dot_Bottom >= 0.0f) // we are between the top and bottom.
{
// project posMinusTop onto bottomMinusTop and move to world cords.
const float3 positionProjection = dot_Top * bottomMinusTop / sqrMag(bottomMinusTop) + top;
float dist = distance(positionProjection, position);
dist = collider.radius * SKIN_WIDTH - clamp(0.0, collider.radius * SKIN_WIDTH, dist);
desiredPosition += normalize(position - positionProjection) * dist;
}
return desiredPosition;
}
float3 applyColliders(float3 desiredPosition)
{
for (int i = 0; i < CollidersCount; i++)
{
const ColliderStruct collider = ColliderBuffer[i];
if (ColliderBuffer[i].position2.x == -1000) //For now -1000 means, that it's a single sphere collider.
{
desiredPosition = desiredPosition = sphereCollide(collider, desiredPosition);
}
else
{
desiredPosition = sphereCollide(collider, desiredPosition);
desiredPosition = sphereCollide(collider, desiredPosition);
desiredPosition = capsuleMiddleCollide(collider, desiredPosition);
}
}
return desiredPosition;
}
void writeNormal(const uint furMeshLeftIndex, const uint furMeshRightIndex, const float3 sourceMeshNormal, float3 tangent)
{
float3 left = normalize(cross(tangent, float3(0, 1, 0)));
float3 normal = cross(left, tangent);
normal = lerp(sourceMeshNormal, normal, sourceMeshNormalToStrandNormalPercent);
writeVector3(furMeshLeftIndex, SIZEOF_FLOAT3, normal);
writeVector3(furMeshRightIndex, SIZEOF_FLOAT3, normal);
}