|
| 1 | +#version 460 core |
| 2 | + |
| 3 | +// yeeted from minshu https://github.com/FabianFG/CUE4Parse/commit/61cef25b8eef4160651ee41e2b1ceefc5135803f |
| 4 | + |
| 5 | +struct GpuSplineMeshParams { |
| 6 | + int ForwardAxis; |
| 7 | + float SplineBoundaryMin; |
| 8 | + float SplineBoundaryMax; |
| 9 | + bool bSmoothInterpRollScale; |
| 10 | + |
| 11 | + vec3 MeshOrigin; |
| 12 | + vec3 MeshBoxExtent; |
| 13 | + |
| 14 | + vec3 StartPos; |
| 15 | + float StartRoll; |
| 16 | + vec3 StartTangent; |
| 17 | + vec2 StartScale; |
| 18 | + vec2 StartOffset; |
| 19 | + vec3 EndPos; |
| 20 | + float EndRoll; |
| 21 | + vec3 EndTangent; |
| 22 | + vec2 EndScale; |
| 23 | + vec2 EndOffset; |
| 24 | + |
| 25 | + vec3 SplineUpDir; |
| 26 | +}; |
| 27 | + |
| 28 | +layout(std430, binding = 3) buffer SplineParameters |
| 29 | +{ |
| 30 | + GpuSplineMeshParams uSplineParameters[]; |
| 31 | +}; |
| 32 | + |
| 33 | +uniform bool uIsSpline; |
| 34 | + |
| 35 | +vec3 getSafeNormal(vec3 vector) { |
| 36 | + float squareSum = dot(vector, vector); |
| 37 | + |
| 38 | + if (squareSum == 1.0) { |
| 39 | + return vector; |
| 40 | + } |
| 41 | + |
| 42 | + if (squareSum < 1e-8f) { |
| 43 | + return vec3(0.0); // Return a zero vector |
| 44 | + } |
| 45 | + |
| 46 | + // Calculate the scale factor to normalize the vector |
| 47 | + float scale = inversesqrt(squareSum); |
| 48 | + return vector * scale; |
| 49 | +} |
| 50 | + |
| 51 | +float GetAxisValueRef(int forwardAxis, vec3 pos) |
| 52 | +{ |
| 53 | + switch (forwardAxis) |
| 54 | + { |
| 55 | + case 0: return pos.x; |
| 56 | + case 1: return pos.y; |
| 57 | + case 2: return pos.z; |
| 58 | + default: return 0; |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +void SetAxisValueRef(int forwardAxis, inout vec3 pos, float v) |
| 63 | +{ |
| 64 | + switch (forwardAxis) |
| 65 | + { |
| 66 | + case 0: pos.x = v; break; |
| 67 | + case 1: pos.y = v; break; |
| 68 | + case 2: pos.z = v; break; |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +vec3 SplineEvalTangent(GpuSplineMeshParams params, float a) |
| 73 | +{ |
| 74 | + vec3 c = (6 * params.StartPos) + (3 * params.StartTangent) + (3 * params.EndTangent) - (6 * params.EndPos); |
| 75 | + vec3 d = (-6 * params.StartPos) - (4 * params.StartTangent) - (2 * params.EndTangent) + (6 * params.EndPos); |
| 76 | + vec3 e = params.StartTangent; |
| 77 | + |
| 78 | + float a2 = a * a; |
| 79 | + |
| 80 | + return (c * a2) + (d * a) + e; |
| 81 | +} |
| 82 | + |
| 83 | +vec3 SplineEvalDir(GpuSplineMeshParams params, float a) |
| 84 | +{ |
| 85 | + return getSafeNormal(SplineEvalTangent(params, a)); |
| 86 | +} |
| 87 | + |
| 88 | +vec3 SplineEvalPos(GpuSplineMeshParams params, float a) |
| 89 | +{ |
| 90 | + float a2 = a * a; |
| 91 | + float a3 = a2 * a; |
| 92 | + |
| 93 | + return (((2 * a3) - (3 * a2) + 1) * params.StartPos) + ((a3 - (2 * a2) + a) * params.StartTangent) + ((a3 - a2) * params.EndTangent) + (((-2 * a3) + (3 * a2)) * params.EndPos); |
| 94 | +} |
| 95 | + |
| 96 | +vec3 ComputeRatioAlongSpline(GpuSplineMeshParams params, float distanceAlong) |
| 97 | +{ |
| 98 | + float alpha = 0f; |
| 99 | + float minT = 0f; |
| 100 | + float maxT = 1f; |
| 101 | + |
| 102 | + const float SmallNumber = 1e-8f; |
| 103 | + bool bHasCustomBoundary = abs(params.SplineBoundaryMin - params.SplineBoundaryMax) > SmallNumber; |
| 104 | + if (bHasCustomBoundary) |
| 105 | + { |
| 106 | + float splineLength = params.SplineBoundaryMax - params.SplineBoundaryMin; |
| 107 | + if (splineLength > 0) |
| 108 | + { |
| 109 | + alpha = (distanceAlong - params.SplineBoundaryMin) / splineLength; |
| 110 | + } |
| 111 | + |
| 112 | + float boundMin = GetAxisValueRef(params.ForwardAxis, params.MeshOrigin - params.MeshBoxExtent); |
| 113 | + float boundMax = GetAxisValueRef(params.ForwardAxis, params.MeshOrigin + params.MeshBoxExtent); |
| 114 | + |
| 115 | + float boundMinT = (boundMin - params.SplineBoundaryMin) / (params.SplineBoundaryMax - params.SplineBoundaryMin); |
| 116 | + float boundMaxT = (boundMax - params.SplineBoundaryMin) / (params.SplineBoundaryMax - params.SplineBoundaryMin); |
| 117 | + |
| 118 | + const float MaxSplineExtrapolation = 4.0f; |
| 119 | + minT = max(-MaxSplineExtrapolation, boundMinT); |
| 120 | + maxT = min(boundMaxT, MaxSplineExtrapolation); |
| 121 | + } |
| 122 | + else |
| 123 | + { |
| 124 | + float meshMinZ = GetAxisValueRef(params.ForwardAxis, params.MeshOrigin) - GetAxisValueRef(params.ForwardAxis, params.MeshBoxExtent); |
| 125 | + float meshRangeZ = 2 * GetAxisValueRef(params.ForwardAxis, params.MeshBoxExtent); |
| 126 | + |
| 127 | + if (meshRangeZ > SmallNumber) { |
| 128 | + alpha = (distanceAlong - meshMinZ) / meshRangeZ; |
| 129 | + } |
| 130 | + } |
| 131 | + return vec3(alpha, minT, maxT); |
| 132 | +} |
| 133 | + |
| 134 | +mat4 CalcSliceTransformAtSplineOffset(GpuSplineMeshParams params, vec3 computed) |
| 135 | +{ |
| 136 | + float alpha = computed.x; |
| 137 | + float minT = computed.y; |
| 138 | + float maxT = computed.z; |
| 139 | + |
| 140 | + float hermiteAlpha = params.bSmoothInterpRollScale ? smoothstep(0.0f, 1.0f, alpha) : alpha; |
| 141 | + |
| 142 | + vec3 splinePos; |
| 143 | + vec3 splineDir; |
| 144 | + if (alpha < minT) |
| 145 | + { |
| 146 | + vec3 startTangent = SplineEvalTangent(params, minT); |
| 147 | + splinePos = SplineEvalPos(params, minT) + (startTangent * (alpha - minT)); |
| 148 | + splineDir = getSafeNormal(startTangent); |
| 149 | + } |
| 150 | + else if (alpha > maxT) |
| 151 | + { |
| 152 | + vec3 endTangent = SplineEvalTangent(params, maxT); |
| 153 | + splinePos = SplineEvalPos(params, maxT) + (endTangent * (alpha - maxT)); |
| 154 | + splineDir = getSafeNormal(endTangent); |
| 155 | + } |
| 156 | + else |
| 157 | + { |
| 158 | + splinePos = SplineEvalPos(params, alpha); |
| 159 | + splineDir = SplineEvalDir(params, alpha); |
| 160 | + } |
| 161 | + |
| 162 | + // base |
| 163 | + vec3 baseXVec = getSafeNormal(cross(params.SplineUpDir, splineDir)); |
| 164 | + vec3 baseYVec = getSafeNormal(cross(splineDir, baseXVec)); |
| 165 | + |
| 166 | + // Offset the spline by the desired amount |
| 167 | + vec2 sliceOffset = mix(params.StartOffset, params.EndOffset, hermiteAlpha); |
| 168 | + splinePos += sliceOffset.x * baseXVec; |
| 169 | + splinePos += sliceOffset.y * baseYVec; |
| 170 | + |
| 171 | + // Apply Roll |
| 172 | + float useRoll = mix(params.StartRoll, params.EndRoll, hermiteAlpha); |
| 173 | + float cosAng = cos(useRoll); |
| 174 | + float sinAng = sin(useRoll); |
| 175 | + vec3 xVec = (cosAng * baseXVec) - (sinAng * baseYVec); |
| 176 | + vec3 yVec = (cosAng * baseYVec) + (sinAng * baseXVec); |
| 177 | + |
| 178 | + // Find Scale |
| 179 | + vec2 useScale = mix(params.StartScale, params.EndScale, hermiteAlpha); |
| 180 | + |
| 181 | + // Build overall transform |
| 182 | + mat4 sliceTransform = mat4(0); |
| 183 | + vec3 scale; |
| 184 | + switch (params.ForwardAxis) { |
| 185 | + case 0: |
| 186 | + sliceTransform[0] = vec4(splineDir, 0f); |
| 187 | + sliceTransform[1] = vec4(xVec, 0f); |
| 188 | + sliceTransform[2] = vec4(yVec, 0f); |
| 189 | + sliceTransform[3] = vec4(splinePos, 1f); |
| 190 | + scale = vec3(1, useScale.x, useScale.y); |
| 191 | + break; |
| 192 | + case 1: |
| 193 | + sliceTransform[0] = vec4(yVec, 0f); |
| 194 | + sliceTransform[1] = vec4(splineDir, 0f); |
| 195 | + sliceTransform[2] = vec4(xVec, 0f); |
| 196 | + sliceTransform[3] = vec4(splinePos, 1f); |
| 197 | + scale = vec3(useScale.y, 1, useScale.x); |
| 198 | + break; |
| 199 | + case 2: |
| 200 | + sliceTransform[0] = vec4(xVec, 0f); |
| 201 | + sliceTransform[1] = vec4(yVec, 0f); |
| 202 | + sliceTransform[2] = vec4(splineDir, 0f); |
| 203 | + sliceTransform[3] = vec4(splinePos, 1f); |
| 204 | + scale = vec3(useScale.x, useScale.y, 1); |
| 205 | + break; |
| 206 | + } |
| 207 | + |
| 208 | + mat4 scaleMatrix = mat4( |
| 209 | + vec4(scale.x, 0.0, 0.0, 0.0), |
| 210 | + vec4(0.0, scale.y, 0.0, 0.0), |
| 211 | + vec4(0.0, 0.0, scale.z, 0.0), |
| 212 | + vec4(0.0, 0.0, 0.0, 1.0) |
| 213 | + ); |
| 214 | + |
| 215 | + return sliceTransform * scaleMatrix; |
| 216 | +} |
0 commit comments