123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- /*
- * Modifications Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- //---------------------------------------------------------------------------------------
- // Shader code related to simulating hair strands in compute.
- //-------------------------------------------------------------------------------------
- //
- // Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- //--------------------------------------------------------------------------------------
- #include <HairSimulationComputeSrgs.azsli>
- #include <HairSimulationCommon.azsli>
- //--------------------------------------------------------------------------------------
- //
- // IntegrationAndGlobalShapeConstraints
- //
- // Compute shader to simulate the gravitational force with integration and to maintain the
- // global shape constraints.
- //
- // One thread computes one vertex.
- //
- //--------------------------------------------------------------------------------------
- [numthreads(THREAD_GROUP_SIZE, 1, 1)]
- void IntegrationAndGlobalShapeConstraints(
- uint GIndex : SV_GroupIndex,
- uint3 GId : SV_GroupID,
- uint3 DTid : SV_DispatchThreadID)
- {
- uint globalStrandIndex, localStrandIndex, globalVertexIndex, localVertexIndex, numVerticesInTheStrand, indexForSharedMem, strandType;
- CalcIndicesInVertexLevelMaster(GIndex, GId.x, globalStrandIndex, localStrandIndex, globalVertexIndex, localVertexIndex, numVerticesInTheStrand, indexForSharedMem, strandType);
- // Copy data from init rest data to be used to set updated shared memory
- float4 initialPos = float4(CM_TO_METERS,CM_TO_METERS,CM_TO_METERS,1.0) * g_InitialHairPositions[globalVertexIndex]; // rest position
- // Apply bone skinning to initial position
- BoneSkinningData skinningData = g_BoneSkinningData[globalStrandIndex];
- float4 bone_quat;
- initialPos.xyz = ApplyVertexBoneSkinning(initialPos.xyz, skinningData, bone_quat);
- // position when this step starts. In other words, a position from the last step.
- sharedPos[indexForSharedMem] = GetSharedPosition(globalVertexIndex);
- float4 currentPos = sharedPos[indexForSharedMem];
- // float4 currentPos = sharedPos[indexForSharedMem] = g_HairVertexPositions[globalVertexIndex];
- GroupMemoryBarrierWithGroupSync();
- // Integrate
- float dampingCoeff = GetDamping(strandType);
- float4 oldPos = g_HairVertexPositionsPrev[globalVertexIndex];
- // reset if we got teleported
- if (g_ResetPositions != 0.0f)
- { // Originally part of the data here was NaN as the original TressFX code wrote number
- // vertices including the follow hair although the shader accounts for that, hence
- // memory was overwriten. In our implementation the memory resides all within
- // a single buffer and this would actively overwrite the rest of the buffer hence
- // destroying the original contexnt.
- currentPos = initialPos;
- g_HairVertexPositions[globalVertexIndex] = initialPos;
- g_HairVertexPositionsPrev[globalVertexIndex] = initialPos;
- g_HairVertexPositionsPrevPrev[globalVertexIndex] = initialPos;
- oldPos = initialPos;
- }
- // skipping all the physics simulation in between
- if ( IsMovable(currentPos) )
- sharedPos[indexForSharedMem].xyz = Integrate(currentPos.xyz, oldPos.xyz, initialPos.xyz, dampingCoeff);
- else
- sharedPos[indexForSharedMem] = initialPos;
- // Global Shape Constraints
- float stiffnessForGlobalShapeMatching = GetGlobalStiffness(strandType);
- float globalShapeMatchingEffectiveRange = GetGlobalRange(strandType);
- if ( stiffnessForGlobalShapeMatching > 0 && globalShapeMatchingEffectiveRange )
- {
- if ( IsMovable(sharedPos[indexForSharedMem]) )
- {
- if ( (float)localVertexIndex < globalShapeMatchingEffectiveRange * (float)numVerticesInTheStrand )
- {
- float factor = stiffnessForGlobalShapeMatching;
- float3 del = factor * (initialPos - sharedPos[indexForSharedMem]).xyz;
- sharedPos[indexForSharedMem].xyz += del;
- }
- }
- }
- // update global position buffers
- UpdateFinalVertexPositions(currentPos, sharedPos[indexForSharedMem], globalVertexIndex);
- }
- //--------------------------------------------------------------------------------------
- //
- // Calculate Strand Level Data
- //
- // Propagate velocity shock resulted by attached based mesh
- //
- // One thread computes two vertices within a strand.
- //
- //--------------------------------------------------------------------------------------
- [numthreads(THREAD_GROUP_SIZE, 1, 1)]
- void CalculateStrandLevelData(
- uint GIndex : SV_GroupIndex,
- uint3 GId : SV_GroupID,
- uint3 DTid : SV_DispatchThreadID)
- {
- uint local_id, group_id, globalStrandIndex, numVerticesInTheStrand, globalRootVertexIndex, strandType;
- CalcIndicesInStrandLevelMaster(GIndex, GId.x, globalStrandIndex, numVerticesInTheStrand, globalRootVertexIndex, strandType);
- // Accounting for the right and left side of the strand.
- float4 pos_old_old[2]; // previous previous positions for vertex 0 (root) and vertex 1.
- float4 pos_old[2]; // previous positions for vertex 0 (root) and vertex 1.
- float4 pos_new[2]; // current positions for vertex 0 (root) and vertex 1.
- pos_old_old[0] = g_HairVertexPositionsPrevPrev[globalRootVertexIndex];
- pos_old_old[1] = g_HairVertexPositionsPrevPrev[globalRootVertexIndex + 1];
- pos_old[0] = g_HairVertexPositionsPrev[globalRootVertexIndex];
- pos_old[1] = g_HairVertexPositionsPrev[globalRootVertexIndex + 1];
- pos_new[0] = g_HairVertexPositions[globalRootVertexIndex];
- pos_new[1] = g_HairVertexPositions[globalRootVertexIndex + 1];
- float3 u = normalize(pos_old[1].xyz - pos_old[0].xyz);
- float3 v = normalize(pos_new[1].xyz - pos_new[0].xyz);
- // Compute rotation and translation which transform pos_old to pos_new.
- // Since the first two vertices are immovable, we can assume that there is no scaling during tranform.
- float4 rot = QuatFromTwoUnitVectors(u, v);
- float3 trans = pos_new[0].xyz - MultQuaternionAndVector(rot, pos_old[0].xyz);
- float vspCoeff = GetVelocityShockPropogation();
- float restLength0 = g_HairRestLengthSRV[globalRootVertexIndex];
- float vspAccelThreshold = GetVSPAccelThreshold();
- // Increase the VSP coefficient by checking pseudo-acceleration to handle over-stretching when the character moves very fast
- float accel = length(pos_new[1] - 2.0 * pos_old[1] + pos_old_old[1]);
- if (accel > vspAccelThreshold)
- vspCoeff = 1.0f;
- g_StrandLevelData[globalStrandIndex].vspQuat = rot;
- g_StrandLevelData[globalStrandIndex].vspTranslation = float4(trans, vspCoeff);
- // Skinning
- // Copy data from init rest data to be used to set updated shared memory
- float4 initialPos = float4(CM_TO_METERS,CM_TO_METERS,CM_TO_METERS,1.0) * g_InitialHairPositions[globalRootVertexIndex]; // rest position
- // Apply bone skinning to initial position
- BoneSkinningData skinningData = g_BoneSkinningData[globalStrandIndex];
- float4 bone_quat;
- initialPos.xyz = ApplyVertexBoneSkinning(initialPos.xyz, skinningData, bone_quat);
- g_StrandLevelData[globalStrandIndex].skinningQuat = bone_quat;
- }
- //--------------------------------------------------------------------------------------
- //
- // VelocityShockPropagation
- //
- // Propagate velocity shock resulted by attached based mesh
- //
- // One thread computes a vertex in a strand.
- //
- //--------------------------------------------------------------------------------------
- [numthreads(THREAD_GROUP_SIZE, 1, 1)]
- void VelocityShockPropagation(
- uint GIndex : SV_GroupIndex,
- uint3 GId : SV_GroupID,
- uint3 DTid : SV_DispatchThreadID)
- {
- uint globalStrandIndex, localStrandIndex, globalVertexIndex, localVertexIndex, numVerticesInTheStrand, indexForSharedMem, strandType;
- CalcIndicesInVertexLevelMaster(GIndex, GId.x, globalStrandIndex, localStrandIndex, globalVertexIndex, localVertexIndex, numVerticesInTheStrand, indexForSharedMem, strandType);
- // The first two vertices are the ones attached to the skin
- if (localVertexIndex < 2)
- return;
- float4 vspQuat = g_StrandLevelData[globalStrandIndex].vspQuat;
- float4 vspTrans = g_StrandLevelData[globalStrandIndex].vspTranslation;
- float vspCoeff = vspTrans.w;
- float4 pos_new_n = g_HairVertexPositions[globalVertexIndex];
- float4 pos_old_n = g_HairVertexPositionsPrev[globalVertexIndex];
- pos_new_n.xyz = (1.f - vspCoeff) * pos_new_n.xyz + vspCoeff * (MultQuaternionAndVector(vspQuat, pos_new_n.xyz) + vspTrans.xyz);
- pos_old_n.xyz = (1.f - vspCoeff) * pos_old_n.xyz + vspCoeff * (MultQuaternionAndVector(vspQuat, pos_old_n.xyz) + vspTrans.xyz);
- g_HairVertexPositions[globalVertexIndex].xyz = pos_new_n.xyz;
- g_HairVertexPositionsPrev[globalVertexIndex].xyz = pos_old_n.xyz;
- }
- //--------------------------------------------------------------------------------------
- //
- // LocalShapeConstraints
- //
- // Compute shader to maintain the local shape constraints.
- //
- // One thread computes one strand.
- //
- //--------------------------------------------------------------------------------------
- [numthreads(THREAD_GROUP_SIZE, 1, 1)]
- void LocalShapeConstraints(
- uint GIndex : SV_GroupIndex,
- uint3 GId : SV_GroupID,
- uint3 DTid : SV_DispatchThreadID)
- {
- uint local_id, group_id, globalStrandIndex, numVerticesInTheStrand, globalRootVertexIndex, strandType;
- CalcIndicesInStrandLevelMaster(GIndex, GId.x, globalStrandIndex, numVerticesInTheStrand, globalRootVertexIndex, strandType);
- // stiffness for local shape constraints
- float stiffnessForLocalShapeMatching = GetLocalStiffness(strandType);
- // Going beyond the TH will create less stability in convergence
- const float stabilityTH = 0.95f;
- stiffnessForLocalShapeMatching = 0.5f * min(stiffnessForLocalShapeMatching, stabilityTH);
- //--------------------------------------------
- // Local shape constraint for bending/twisting
- //--------------------------------------------
- {
- float4 boneQuat = g_StrandLevelData[globalStrandIndex].skinningQuat;
- // vertex 1 through n-1
- for (uint localVertexIndex = 1; localVertexIndex < numVerticesInTheStrand - 1; localVertexIndex++)
- {
- uint globalVertexIndex = globalRootVertexIndex + localVertexIndex;
- float4 pos = g_HairVertexPositions[globalVertexIndex];
- float4 pos_plus_one = g_HairVertexPositions[globalVertexIndex + 1];
- float4 pos_minus_one = g_HairVertexPositions[globalVertexIndex - 1];
- float3 bindPos = MultQuaternionAndVector(boneQuat, g_InitialHairPositions[globalVertexIndex].xyz * CM_TO_METERS);
- float3 bindPos_plus_one = MultQuaternionAndVector(boneQuat, g_InitialHairPositions[globalVertexIndex + 1].xyz * CM_TO_METERS);
- float3 bindPos_minus_one = MultQuaternionAndVector(boneQuat, g_InitialHairPositions[globalVertexIndex - 1].xyz * CM_TO_METERS);
- float3 lastVec = pos.xyz - pos_minus_one.xyz;
- float3 vecBindPose = bindPos_plus_one - bindPos;
- float3 lastVecBindPose = bindPos - bindPos_minus_one;
- float4 rotGlobal = QuatFromTwoUnitVectors(normalize(lastVecBindPose), normalize(lastVec));
- float3 orgPos_i_plus_1_InGlobalFrame = MultQuaternionAndVector(rotGlobal, vecBindPose) + pos.xyz;
- float3 del = stiffnessForLocalShapeMatching * (orgPos_i_plus_1_InGlobalFrame - pos_plus_one.xyz);
- if (IsMovable(pos))
- pos.xyz -= del.xyz;
- if (IsMovable(pos_plus_one))
- pos_plus_one.xyz += del.xyz;
- g_HairVertexPositions[globalVertexIndex].xyz = pos.xyz;
- g_HairVertexPositions[globalVertexIndex + 1].xyz = pos_plus_one.xyz;
- }
- }
- }
- //--------------------------------------------------------------------------------------
- //
- // LengthConstriantsWindAndCollision
- //
- // Compute shader to move the vertex position based on wind, maintain the lenght constraints
- // and handles collisions.
- //
- // One thread computes one vertex.
- //
- //--------------------------------------------------------------------------------------
- [numthreads(THREAD_GROUP_SIZE, 1, 1)]
- void LengthConstriantsWindAndCollision(uint GIndex : SV_GroupIndex,
- uint3 GId : SV_GroupID,
- uint3 DTid : SV_DispatchThreadID)
- {
- uint globalStrandIndex, localStrandIndex, globalVertexIndex, localVertexIndex, numVerticesInTheStrand, indexForSharedMem, strandType;
- CalcIndicesInVertexLevelMaster(GIndex, GId.x, globalStrandIndex, localStrandIndex, globalVertexIndex, localVertexIndex, numVerticesInTheStrand, indexForSharedMem, strandType);
- uint numOfStrandsPerThreadGroup = g_NumOfStrandsPerThreadGroup;
- //------------------------------
- // Copy data into shared memory
- //------------------------------
- sharedPos[indexForSharedMem] = g_HairVertexPositions[globalVertexIndex];
- sharedLength[indexForSharedMem] = g_HairRestLengthSRV[globalVertexIndex] * CM_TO_METERS;
- GroupMemoryBarrierWithGroupSync();
- /*
- //------------
- // Wind - does not work yet and requires some LTC
- //------------
- if (any(g_Wind.xyz)) // g_Wind.w is the current frame
- {
- float4 force = float4(0, 0, 0, 0);
- if ( localVertexIndex >= 2 && localVertexIndex < numVerticesInTheStrand-1 )
- {
- // combining four winds.
- float a = ((float)(globalStrandIndex % 20))/20.0f;
- float3 w = a* g_Wind.xyz + (1.0f - a) * g_Wind1.xyz + a * g_Wind2.xyz + (1.0f - a) * g_Wind3.xyz;
- // float3 w = float3(5.2, 0, 0);
- uint sharedIndex = localVertexIndex * numOfStrandsPerThreadGroup + localStrandIndex;
- float3 v = sharedPos[sharedIndex].xyz - sharedPos[sharedIndex+numOfStrandsPerThreadGroup].xyz;
- float3 force = -cross(cross(v, w), v);
- sharedPos[sharedIndex].xyz += force*g_TimeStep*g_TimeStep;
- }
- }
- GroupMemoryBarrierWithGroupSync();
- */
- //----------------------------
- // Enforce length constraints
- //----------------------------
- uint a = numVerticesInTheStrand/2.0f;
- uint b = (numVerticesInTheStrand-1)/2.0f;
- int lengthContraintIterations = GetLengthConstraintIterations();
- for ( int iterationE=0; iterationE < lengthContraintIterations; iterationE++ )
- {
- uint sharedIndex = 2 * localVertexIndex * numOfStrandsPerThreadGroup + localStrandIndex;
- // Notice that the following is based on the fact that we are dealing here with two vertices
- // one at each side of the central control point and each should extend towards its side only.
- if( localVertexIndex < a )
- ApplyDistanceConstraint(sharedPos[sharedIndex], sharedPos[sharedIndex+numOfStrandsPerThreadGroup], sharedLength[sharedIndex].x);
- GroupMemoryBarrierWithGroupSync();
- if( localVertexIndex < b )
- ApplyDistanceConstraint(sharedPos[sharedIndex+numOfStrandsPerThreadGroup], sharedPos[sharedIndex+numOfStrandsPerThreadGroup*2], sharedLength[sharedIndex+numOfStrandsPerThreadGroup].x);
- GroupMemoryBarrierWithGroupSync();
- }
- //------------------------------------------
- // Collision handling with capsule objects
- //------------------------------------------
- float4 oldPos = g_HairVertexPositionsPrev[globalVertexIndex];
- bool bAnyColDetected = false; // Adi
- // bool bAnyColDetected = ResolveCapsuleCollisions(sharedPos[indexForSharedMem], oldPos);
- GroupMemoryBarrierWithGroupSync();
- //-------------------
- // Compute tangent
- //-------------------
- // If this is the last vertex in the strand, we can't get tangent from subtracting from the next vertex, need to use last vertex to current
- uint indexForTangent = (localVertexIndex == numVerticesInTheStrand - 1) ? indexForSharedMem - numOfStrandsPerThreadGroup : indexForSharedMem;
- float3 tangent = sharedPos[indexForTangent + numOfStrandsPerThreadGroup].xyz - sharedPos[indexForTangent].xyz;
- g_HairVertexTangents[globalVertexIndex].xyz = normalize(tangent);
- //---------------------------------------
- // clamp velocities, rewrite history
- //---------------------------------------
- float3 positionDelta = sharedPos[indexForSharedMem].xyz - oldPos;
- float speedSqr = dot(positionDelta, positionDelta);
- if (speedSqr > g_ClampPositionDelta * g_ClampPositionDelta) {
- positionDelta *= g_ClampPositionDelta * g_ClampPositionDelta / speedSqr;
- g_HairVertexPositionsPrev[globalVertexIndex].xyz = sharedPos[indexForSharedMem].xyz - positionDelta;
- }
- //---------------------------------------
- // update global position buffers
- //---------------------------------------
- g_HairVertexPositions[globalVertexIndex] = sharedPos[indexForSharedMem];
- if (bAnyColDetected)
- g_HairVertexPositionsPrev[globalVertexIndex] = sharedPos[indexForSharedMem];
- return;
- }
- //--------------------------------------------------------------------------------------
- //
- // UpdateFollowHairVertices
- //
- // Last stage update of the follow hair to follow their guide hair
- //
- // One thread computes one vertex.
- //
- //--------------------------------------------------------------------------------------
- [numthreads(THREAD_GROUP_SIZE, 1, 1)]
- void UpdateFollowHairVertices(
- uint GIndex : SV_GroupIndex,
- uint3 GId : SV_GroupID,
- uint3 DTid : SV_DispatchThreadID)
- {
- uint globalStrandIndex, localStrandIndex, globalVertexIndex, localVertexIndex, numVerticesInTheStrand, indexForSharedMem, strandType;
- CalcIndicesInVertexLevelMaster(GIndex, GId.x, globalStrandIndex, localStrandIndex, globalVertexIndex, localVertexIndex, numVerticesInTheStrand, indexForSharedMem, strandType);
- sharedPos[indexForSharedMem] = GetSharedPosition(globalVertexIndex); // g_HairVertexPositions[globalVertexIndex];
- sharedTangent[indexForSharedMem].xyz = GetSharedTangent(globalVertexIndex); // g_HairVertexTangents[globalVertexIndex];
- GroupMemoryBarrierWithGroupSync();
- for ( uint i = 0; i < g_NumFollowHairsPerGuideHair; i++ )
- {
- int globalFollowVertexIndex = globalVertexIndex + numVerticesInTheStrand * (i + 1);
- int globalFollowStrandIndex = globalStrandIndex + i + 1;
- float factor = g_TipSeparationFactor*((float)localVertexIndex / (float)numVerticesInTheStrand) + 1.0f;
- float3 followPos = sharedPos[indexForSharedMem].xyz + factor * CM_TO_METERS * g_FollowHairRootOffset[globalFollowStrandIndex].xyz;
- SetSharedPosition3(globalFollowVertexIndex, followPos);
- // g_HairVertexPositions[globalFollowVertexIndex].xyz = followPos;
- //-----------------------
- // SetSharedTangent(globalFollowVertexIndex, sharedTangent[indexForSharedMem]);
- g_HairVertexTangents[globalFollowVertexIndex] = sharedTangent[indexForSharedMem];
- }
-
- return;
- }
|