Fix hair interpolation for 4.25

#rb none
#jira none
[FYI] charles.derousiers

#ROBOMERGE-SOURCE: CL 12877701 in //UE4/Release-4.25/... via CL 12877703 via CL 12877706
#ROBOMERGE-BOT: RELEASE (Release-Engine-Staging -> Main) (v681-12776863)

[CL 12877707 by michael forot in Main branch]
This commit is contained in:
michael forot
2020-04-17 03:55:56 -04:00
parent 9f23daa688
commit 996fd90144
5 changed files with 156 additions and 18 deletions
@@ -37,14 +37,14 @@ Buffer<uint> SimRootPointIndexBuffer;
Buffer<uint4> AttributeBuffer;
#endif
#if PERMUTATION_DYNAMIC_GEOMETRY == 1 || PERMUTATION_DEBUG == 1 || PERMUTATION_DYNAMIC_GEOMETRY == 2
#if PERMUTATION_DYNAMIC_GEOMETRY >= 1 || PERMUTATION_DEBUG == 1
Buffer<uint> RenVertexToRootIndexBuffer;
Buffer<uint> SimVertexToRootIndexBuffer;
#endif
RWBuffer<uint4> OutRenderDeformedPositionBuffer;
#if PERMUTATION_DYNAMIC_GEOMETRY == 1 || PERMUTATION_DYNAMIC_GEOMETRY == 2
#if PERMUTATION_DYNAMIC_GEOMETRY >= 1
// Compact all these buffers into 2 buffers: translation + quaternion
Buffer<float4> RestPosition0Buffer;
@@ -117,6 +117,32 @@ float3 ComputeDynamicGeometryOffset(
return (LocalDeformedGuidePoint - LocalRestGuidePoint) * GuideVertexWeight;
}
float3 ComputeTranslateGeometryOffset(uint GuideIndex, float GuideVertexWeight)
{
const float3 RestGuidePoint = f16tof32(SimRestPosePositionBuffer[GuideIndex].xyz) -
f16tof32(SimRestPosePositionBuffer[SimRootPointIndexBuffer[GuideIndex]].xyz) ;
const float3 DeformedGuidePoint = f16tof32(DeformedSimPositionBuffer[GuideIndex].xyz) -
f16tof32(DeformedSimPositionBuffer[SimRootPointIndexBuffer[GuideIndex]].xyz) ;
return (DeformedGuidePoint - RestGuidePoint) * GuideVertexWeight;
}
float3 ComputeRotateGeometryOffset(uint GuideIndex, float GuideVertexWeight,
FHairMeshTriangle RestTriangle,
FHairMeshTriangle DeformedTriangle)
{
const float3 RestGuidePoint = f16tof32(SimRestPosePositionBuffer[GuideIndex].xyz) -
f16tof32(SimRestPosePositionBuffer[SimRootPointIndexBuffer[GuideIndex]].xyz) ;
const float3 LocalRestGuidePoint = VectorToTriangle(RestGuidePoint, RestTriangle);
const float3 DeformedGuidePoint = f16tof32(DeformedSimPositionBuffer[GuideIndex].xyz) -
f16tof32(DeformedSimPositionBuffer[SimRootPointIndexBuffer[GuideIndex]].xyz) ;
const float3 LocalDeformedGuidePoint = VectorToTriangle(DeformedGuidePoint, DeformedTriangle);
return (LocalDeformedGuidePoint - LocalRestGuidePoint) * GuideVertexWeight;
}
// Compute the new hair width and return if the current vertex is valid (true), or if it needs to be clipped (false)
bool ScaleAndClip(uint ControlPointId, inout uint InPackedAlpha)
{
@@ -278,14 +304,20 @@ void MainCS(uint2 DispatchThreadId : SV_DispatchThreadID)
}
#endif
// 3. Skin transformation
// Apply dynamic mesh deformation (translation)
// 3. Linear blend skinning (translation)
#if PERMUTATION_DYNAMIC_GEOMETRY == 2
{
uint4 PackedRestPosition = RenderRestPosePositionBuffer[VertexIndex];
const float3 RestControlPoint = f16tof32(PackedRestPosition.xyz) + InRenderHairPositionOffset;
float3 ControlPoint = RestControlPoint;
const uint RootIndex = RenVertexToRootIndexBuffer[VertexIndex];
const float3 RootBarycentric = DecodeBarycentrics(RootBarycentricBuffer[RootIndex]);
const FHairMeshTriangle RestTriangle = GetTriangleTransformation(RootIndex, RestPosition0Buffer, RestPosition1Buffer, RestPosition2Buffer);
const FHairMeshTriangle DeformedTriangle = GetTriangleTransformation(RootIndex, DeformedPosition0Buffer, DeformedPosition1Buffer, DeformedPosition2Buffer);
ControlPoint -= RootBarycentric.x * RestTriangle.P0 + RootBarycentric.y * RestTriangle.P1 + RootBarycentric.z * RestTriangle.P2;
float3 CurrOffset = 0;
#if PERMUTATION_SIMULATION == 1
@@ -295,19 +327,13 @@ void MainCS(uint2 DispatchThreadId : SV_DispatchThreadID)
const uint GuideIndex0 = GuideVertexIndices[K];
const uint GuideIndex1 = GuideIndex0 + 1;
const float3 Offset0 = ComputeLocalGeometryOffset(GuideIndex0, GuideVertexWeights[K]);
const float3 Offset1 = ComputeLocalGeometryOffset(GuideIndex1, GuideVertexWeights[K]);
const float3 Offset0 = ComputeTranslateGeometryOffset(GuideIndex0, 1.0);
const float3 Offset1 = ComputeTranslateGeometryOffset(GuideIndex1, 1.0);
CurrOffset += lerp(Offset0, Offset1, GuideVertexLerps[K]);
CurrOffset += GuideVertexWeights[K] * lerp(Offset0, Offset1, GuideVertexLerps[K]);
}
#endif
const uint RootIndex = RenVertexToRootIndexBuffer[VertexIndex];
const float3 RootBarycentric = DecodeBarycentrics(RootBarycentricBuffer[RootIndex]);
const FHairMeshTriangle RestTriangle = GetTriangleTransformation(RootIndex, RestPosition0Buffer, RestPosition1Buffer, RestPosition2Buffer);
const FHairMeshTriangle DeformedTriangle = GetTriangleTransformation(RootIndex, DeformedPosition0Buffer, DeformedPosition1Buffer, DeformedPosition2Buffer);
ControlPoint -= RootBarycentric.x * RestTriangle.P0 + RootBarycentric.y * RestTriangle.P1 + RootBarycentric.z * RestTriangle.P2;
ControlPoint += RootBarycentric.x * DeformedTriangle.P0 + RootBarycentric.y * DeformedTriangle.P1 + RootBarycentric.z * DeformedTriangle.P2;
const bool bIsValid = ScaleAndClip(VertexIndex, PackedRestPosition.w);
@@ -317,6 +343,93 @@ void MainCS(uint2 DispatchThreadId : SV_DispatchThreadID)
}
#endif
// 4. Linear blend skinning (rotation)
#if PERMUTATION_DYNAMIC_GEOMETRY == 3
{
uint4 PackedRestPosition = RenderRestPosePositionBuffer[VertexIndex];
const float3 RestControlPoint = f16tof32(PackedRestPosition.xyz) + InRenderHairPositionOffset;
float3 ControlPoint = RestControlPoint;
const uint RootIndex = RenVertexToRootIndexBuffer[VertexIndex];
const float3 RootBarycentric = DecodeBarycentrics(RootBarycentricBuffer[RootIndex]);
const FHairMeshTriangle RestTriangle = GetTriangleTransformation(RootIndex, RestPosition0Buffer, RestPosition1Buffer, RestPosition2Buffer);
const FHairMeshTriangle DeformedTriangle = GetTriangleTransformation(RootIndex, DeformedPosition0Buffer, DeformedPosition1Buffer, DeformedPosition2Buffer);
ControlPoint -= RootBarycentric.x * RestTriangle.P0 + RootBarycentric.y * RestTriangle.P1 + RootBarycentric.z * RestTriangle.P2;
float3 CurrOffset = 0;
#if PERMUTATION_SIMULATION == 1
for (uint K = 0; K < 3; ++K)
{
const uint GuideIndex0 = GuideVertexIndices[K];
const uint GuideIndex1 = GuideIndex0 + 1;
const uint RootIndexG = SimVertexToRootIndexBuffer[GuideIndex0];
const FHairMeshTriangle RestTriangleG = GetTriangleTransformation(RootIndexG, SimRestPosition0Buffer, SimRestPosition1Buffer, SimRestPosition2Buffer);
const FHairMeshTriangle DeformedTriangleG = GetTriangleTransformation(RootIndexG, SimDeformedPosition0Buffer, SimDeformedPosition1Buffer, SimDeformedPosition2Buffer);
const float3 LocalPoint = VectorToTriangle(ControlPoint,RestTriangleG);
const float3 Offset0 = ComputeRotateGeometryOffset(GuideIndex0, 1.0, RestTriangleG, DeformedTriangleG);
const float3 Offset1 = ComputeRotateGeometryOffset(GuideIndex1, 1.0, RestTriangleG, DeformedTriangleG);
CurrOffset += GuideVertexWeights[K] * VectorToWorld(lerp(Offset0, Offset1, GuideVertexLerps[K])+LocalPoint,DeformedTriangleG);
}
#endif
ControlPoint = RootBarycentric.x * DeformedTriangle.P0 + RootBarycentric.y * DeformedTriangle.P1 + RootBarycentric.z * DeformedTriangle.P2;
const bool bIsValid = ScaleAndClip(VertexIndex, PackedRestPosition.w);
WorldVertexPosition = bIsValid ? ControlPoint + CurrOffset : float3(1.#INF, 1.#INF, 1.#INF);
OutRenderDeformedPositionBuffer[VertexIndex] = float4(f32tof16(WorldVertexPosition - OutHairPositionOffset), PackedRestPosition.w);
}
#endif
// 5. Linear blend skinning (translation + rotation)
#if PERMUTATION_DYNAMIC_GEOMETRY == 3
{
uint4 PackedRestPosition = RenderRestPosePositionBuffer[VertexIndex];
const float3 RestControlPoint = f16tof32(PackedRestPosition.xyz) + InRenderHairPositionOffset;
float3 ControlPoint = RestControlPoint;
const uint RootIndex = RenVertexToRootIndexBuffer[VertexIndex];
const float3 RootBarycentric = DecodeBarycentrics(RootBarycentricBuffer[RootIndex]);
const FHairMeshTriangle RestTriangle = GetTriangleTransformation(RootIndex, RestPosition0Buffer, RestPosition1Buffer, RestPosition2Buffer);
const FHairMeshTriangle DeformedTriangle = GetTriangleTransformation(RootIndex, DeformedPosition0Buffer, DeformedPosition1Buffer, DeformedPosition2Buffer);
float3 CurrOffset = 0;
#if PERMUTATION_SIMULATION == 1
for (uint K = 0; K < 3; ++K)
{
const uint GuideIndex0 = GuideVertexIndices[K];
const uint GuideIndex1 = GuideIndex0 + 1;
const uint RootIndexG = SimVertexToRootIndexBuffer[GuideIndex0];
const float3 RootBarycentricG = DecodeBarycentrics(RootBarycentricBuffer[RootIndexG]);
const FHairMeshTriangle RestTriangleG = GetTriangleTransformation(RootIndexG, SimRestPosition0Buffer, SimRestPosition1Buffer, SimRestPosition2Buffer);
const FHairMeshTriangle DeformedTriangleG = GetTriangleTransformation(RootIndexG, SimDeformedPosition0Buffer, SimDeformedPosition1Buffer, SimDeformedPosition2Buffer);
const float3 LocalPoint = ToTriangle(ControlPoint,RootBarycentricG,RestTriangleG);
const float3 Offset0 = ComputeDynamicGeometryOffset(GuideIndex0, 1.0, RestTriangleG, DeformedTriangleG, RootBarycentricG);
const float3 Offset1 = ComputeDynamicGeometryOffset(GuideIndex1, 1.0, RestTriangleG, DeformedTriangleG, RootBarycentricG);
CurrOffset += GuideVertexWeights[K] * ToWorld(lerp(Offset0, Offset1, GuideVertexLerps[K])+LocalPoint,RootBarycentricG,DeformedTriangleG);
}
#endif
const bool bIsValid = ScaleAndClip(VertexIndex, PackedRestPosition.w);
WorldVertexPosition = bIsValid ? CurrOffset : float3(1.#INF, 1.#INF, 1.#INF);
OutRenderDeformedPositionBuffer[VertexIndex] = float4(f32tof16(WorldVertexPosition - OutHairPositionOffset), PackedRestPosition.w);
}
#endif
#if PERMUTATION_DEBUG == 1
if (HairDebugMode == 1)
{