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.

208 lines
9.1 KiB
Plaintext

#pragma kernel AllInOneKernel
#include "VerletSimulationInclude.hlsl"
#include "HairRendererInclude.hlsl"
#include "Thread.hlsl"
#include "../NormalHelperInclude.cginc"
#pragma multi_compile __ INITIALIZE_VERLET_NODES
#pragma multi_compile __ VERLET_ENABLED
#pragma multi_compile __ HAS_COLLIDERS
#pragma multi_compile __ COLLIDE_WITH_SOURCE_MESH
#pragma multi_compile __ USE_FORWARD_COLLISION
#pragma multi_compile __ IS_SKINNED
#pragma warning( disable : 4000 )
#pragma warning( disable : 4714 )
StructuredBuffer<HairStrandPoint> hairStrandPoints;
uniform float strandsWidth;
uniform StructuredBuffer<MeshProperties> sourceMesh;
uniform StructuredBuffer<float> strandShapeBuffer;
uniform float extraScale;
uniform float keepShapeStrength;
void initializeVerletNode(uint index, float3 position)
{
#if defined(INITIALIZE_VERLET_NODES)
verletNodes[index].position = position;
verletNodes[index].prevPosition = position;
#endif
}
void getHairCurPrevNextPosition(int index, bool isFirst, bool isLast, out float3 current, out float3 next,
out float3 prev, out float3 sourceNormal)
{
#if defined(IS_SKINNED)
const HairStrandPoint hairStrandPointCurrent = hairStrandPoints[index];
const MeshProperties sm1 = sourceMesh[(int)hairStrandPointCurrent.triangleIndices.x];
const MeshProperties sm2 = sourceMesh[(int)hairStrandPointCurrent.triangleIndices.y];
const MeshProperties sm3 = sourceMesh[(int)hairStrandPointCurrent.triangleIndices.z];
const float3 n1 = sm1.sourceNormal;
const float3 n2 = sm2.sourceNormal;
const float3 n3 = sm3.sourceNormal;
const float3 normal = Interpolate3(n1, n2, n3, hairStrandPointCurrent.barycentricCoordinate);
sourceNormal = mul(objectRotationMatrix, float4(normal, 1)).xyz;
const float3 v1 = sm1.sourceVertex;
const float3 v2 = sm2.sourceVertex;
const float3 v3 = sm3.sourceVertex;
const float3 rootPosition = Interpolate3(v1, v2, v3, hairStrandPointCurrent.barycentricCoordinate);
current = rootPosition + normalize(normal - hairStrandPointCurrent.rotationDiffFromNormal) * hairStrandPointCurrent.distanceToRoot;
current = mul(localToWorldMatrix, float4(current, 1)).xyz;
initializeVerletNode(index, current);
if (!isLast)
{
const HairStrandPoint hairStrandPointNext = hairStrandPoints[index + 1];
next = rootPosition + normalize(normal - hairStrandPointNext.rotationDiffFromNormal) * hairStrandPointNext.distanceToRoot;
next = mul(localToWorldMatrix, float4(next, 1)).xyz;
initializeVerletNode(index + 1, next);
}
if (!isFirst)
{
const HairStrandPoint hairStrandPointPrev = hairStrandPoints[index - 1];
prev = rootPosition + normalize(normal - hairStrandPointPrev.rotationDiffFromNormal) * hairStrandPointPrev.distanceToRoot;
prev = mul(localToWorldMatrix, float4(prev, 1)).xyz;
initializeVerletNode(index - 1, prev);
}
#else
current = mul(localToWorldMatrix, float4(hairStrandPoints[index].barycentricCoordinate, 1)).xyz;
initializeVerletNode(index , current);
//Position is stored in barycentricCoordinate when its not skinned.
if (!isFirst)
{
prev = mul(localToWorldMatrix, float4(hairStrandPoints[index - 1].barycentricCoordinate, 1)).xyz;
initializeVerletNode(index - 1, prev);
}
if (!isLast)
{
next = mul(localToWorldMatrix, float4(hairStrandPoints[index + 1].barycentricCoordinate, 1)).xyz;
initializeVerletNode(index + 1, next);
}
sourceNormal = 0;
#endif
}
THREAD_SIZE
void AllInOneKernel(uint3 id : SV_DispatchThreadID)
{
uint index, localPointIndex, hairStrandIndex;
if (calculateIndicesAndDiscard(id, index, localPointIndex, hairStrandIndex)) return;
const uint hairMeshIndexLeft = index * 2 * furMeshBufferStride;
const uint hairMeshIndexRight = (index * 2 + 1) * furMeshBufferStride;
float3 currentRestPos, prevRestPosition, nextRestPos, sourceNormal;
const bool isFixedNode = localPointIndex == 0;
const bool isNextNodeFixed = localPointIndex == strandPointsCount - 1;
getHairCurPrevNextPosition(index, isFixedNode, isNextNodeFixed, currentRestPos, nextRestPos, prevRestPosition,
sourceNormal);
float3 currentPosition = currentRestPos;
float3 tangent = calculateTangent(currentRestPos, prevRestPosition, nextRestPos, isNextNodeFixed);
verletNodes[index].tangent = tangent;
#if defined(INITIALIZE_VERLET_NODES)
if(!isFixedNode)
{
GroupMemoryBarrierWithGroupSync();
const float3 myRotVec = normalize(currentRestPos - prevRestPosition);
const float3 myRotVec2 = normalize(nextRestPos-currentRestPos );
verletNodes[index].rotationDiffFromPrevNode = verletNodes[index-1].tangent - myRotVec;
verletNodes[index].rotationDiffFromPrevNode2 = tangent - myRotVec2;
}
#endif
GroupMemoryBarrierWithGroupSync();
const float vertMoveAbility = (float)localPointIndex / (float)(strandPointsCount - 1);
#if defined(VERLET_ENABLED)
if (localPointIndex > numberOfFixedNodesInStrand)
{
velocityGravityAndCollision(
currentRestPos,
isFixedNode,
vertMoveAbility,
0,
index
);
float3 pos = verletNodes[index].position;
pos += (currentRestPos - pos) * keepShapeStrength * deltaTime;
verletNodes[index].position = pos;
const float shapeConstraintIntensity = lerp(shapeConstraintRoot,shapeConstraintTip, vertMoveAbility);
constraints(
index,
currentRestPos,
nextRestPos,
prevRestPosition,
isNextNodeFixed,
shapeConstraintIntensity
);
currentPosition = verletNodes[index].position;
}else
{
verletNodes[index].position = currentPosition;
}
#endif
tangent = calculateTangent(currentRestPos, verletNodes[index - 1].position, verletNodes[index + 1].position,
isNextNodeFixed);
const float3 right = normalize(cross(tangent, normalize(currentPosition - worldSpaceCameraPos)));
const float3 left = normalize(cross(tangent, float3(0, 1, 0)));
// Calculate normal
#if defined(IS_SKINNED)
float3 normal = lerp(sourceNormal, cross(left, tangent), sourceMeshNormalToStrandNormalPercent);
#else
float3 normal = cross(left, tangent);
#endif
const float3 oldPositionLeft = loadSourceVertex(hairMeshIndexLeft);
const float3 oldPositionRight = loadSourceVertex(hairMeshIndexRight);
const float widthFromShape = strandShapeBuffer[localPointIndex] * strandsWidth * extraScale;
const float3 leftVertex = currentPosition - right * widthFromShape;
const float3 leftRight = currentPosition + right * widthFromShape;
//Vertex position
writeVector3(hairMeshIndexLeft, 0, leftVertex);
writeVector3(hairMeshIndexRight, 0, leftRight);
//Normal
writeVector3(hairMeshIndexLeft, SIZEOF_FLOAT3, normal);
writeVector3(hairMeshIndexRight, SIZEOF_FLOAT3, normal);
//Tangent
writeVector4(hairMeshIndexLeft, SIZEOF_FLOAT3 * 2, float4(tangent, 1));
writeVector4(hairMeshIndexRight, SIZEOF_FLOAT3 * 2, float4(tangent, 1));
//UV2
#if defined(INITIALIZE_VERLET_NODES)
float xOffset = rand((float)hairStrandIndex) > 0.25 ? 0.5 : 0;
float yOffset = rand((float)hairStrandIndex * 1.32) > 0.25 ? 0.5 : 0;
//Card UV2 we only need to write it the first time
writeVector2(hairMeshIndexLeft, SIZEOF_FLOAT3 * 2 + SIZEOF_FLOAT4 * 2 + SIZEOF_FLOAT2, float2(0.5 + xOffset, vertMoveAbility * 0.5 + yOffset));
writeVector2(hairMeshIndexRight, SIZEOF_FLOAT3 * 2 + SIZEOF_FLOAT4 * 2 + SIZEOF_FLOAT2, float2(0 + xOffset, vertMoveAbility * 0.5 + yOffset));
//Source mesh UV
float2 uv = hairStrandPoints[index].uv;
writeVector2(hairMeshIndexLeft, SIZEOF_FLOAT3 * 2 + SIZEOF_FLOAT4 * 2, uv);
writeVector2(hairMeshIndexRight, SIZEOF_FLOAT3 * 2 + SIZEOF_FLOAT4 * 2, uv);
//Vertex Color
writeVector4(hairMeshIndexLeft, SIZEOF_FLOAT3 * 2 + SIZEOF_FLOAT4, float4(1, 1, 1, 1));
writeVector4(hairMeshIndexRight, SIZEOF_FLOAT3 * 2 + SIZEOF_FLOAT4, float4(1, 1, 1, 1));
#endif
//Write the old positions to UV3-4
writeVector2(hairMeshIndexLeft, SIZEOF_FLOAT3 * 2 + SIZEOF_FLOAT4 * 2 + SIZEOF_FLOAT2 * 2,
float2(oldPositionLeft.x, oldPositionLeft.y));
writeVector2(hairMeshIndexLeft, SIZEOF_FLOAT3 * 2 + SIZEOF_FLOAT4 * 2 + SIZEOF_FLOAT2 * 3,
float2(oldPositionLeft.z, (float)localPointIndex));
writeVector2(hairMeshIndexRight, SIZEOF_FLOAT3 * 2 + SIZEOF_FLOAT4 * 2 + SIZEOF_FLOAT2 * 2,
float2(oldPositionRight.x, oldPositionRight.y));
writeVector2(hairMeshIndexRight, SIZEOF_FLOAT3 * 2 + SIZEOF_FLOAT4 * 2 + SIZEOF_FLOAT2 * 3,
float2(oldPositionRight.z, (float)localPointIndex));
}