#ifndef SG_MOTION_VECTORS_PASS_INCLUDED #define SG_MOTION_VECTORS_PASS_INCLUDED #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/MotionVectorsCommon.hlsl" struct MotionVectorPassAttributes { float3 previousPositionOS : TEXCOORD4; // Contains previous frame local vertex position (for skinned meshes) #if defined (_ADD_PRECOMPUTED_VELOCITY) float3 alembicMotionVectorOS : TEXCOORD5; // Alembic precomputed object space motion vector (offset from last frame's position) #endif }; // Note: these will have z == 0.0f in the pixel shader to save on bandwidth struct MotionVectorPassVaryings { float4 positionCSNoJitter; float4 previousPositionCSNoJitter; }; struct PackedMotionVectorPassVaryings { float3 positionCSNoJitter : CLIP_POSITION_NO_JITTER; float3 previousPositionCSNoJitter : PREVIOUS_CLIP_POSITION_NO_JITTER; }; PackedMotionVectorPassVaryings PackMotionVectorVaryings(MotionVectorPassVaryings regularVaryings) { PackedMotionVectorPassVaryings packedVaryings; packedVaryings.positionCSNoJitter = regularVaryings.positionCSNoJitter.xyw; packedVaryings.previousPositionCSNoJitter = regularVaryings.previousPositionCSNoJitter.xyw; return packedVaryings; } MotionVectorPassVaryings UnpackMotionVectorVaryings(PackedMotionVectorPassVaryings packedVaryings) { MotionVectorPassVaryings regularVaryings; regularVaryings.positionCSNoJitter = float4(packedVaryings.positionCSNoJitter.xy, 0, packedVaryings.positionCSNoJitter.z); regularVaryings.previousPositionCSNoJitter = float4(packedVaryings.previousPositionCSNoJitter.xy, 0, packedVaryings.previousPositionCSNoJitter.z); return regularVaryings; } float3 GetLastFrameDeformedPosition(Attributes input, MotionVectorPassOutput currentFrameMvData, float3 previousPositionOS) { Attributes lastFrameInputAttributes = input; lastFrameInputAttributes.positionOS = previousPositionOS; VertexDescriptionInputs lastFrameVertexDescriptionInputs = BuildVertexDescriptionInputs(lastFrameInputAttributes); #if defined(AUTOMATIC_TIME_BASED_MOTION_VECTORS) && defined(GRAPH_VERTEX_USES_TIME_PARAMETERS_INPUT) lastFrameVertexDescriptionInputs.TimeParameters = _LastTimeParameters.xyz; #endif VertexDescription lastFrameVertexDescription = VertexDescriptionFunction(lastFrameVertexDescriptionInputs #if defined(HAVE_VFX_MODIFICATION) , currentFrameMvData.vfxGraphProperties #endif ); #if defined(HAVE_VFX_MODIFICATION) lastFrameInputAttributes.positionOS = lastFrameVertexDescription.Position.xyz; lastFrameInputAttributes = VFXTransformMeshToPreviousElement(lastFrameInputAttributes, currentFrameMvData.vfxElementAttributes); previousPositionOS = lastFrameInputAttributes.positionOS; #else previousPositionOS = lastFrameVertexDescription.Position.xyz; #endif return previousPositionOS; } // ------------------------------------- // Vertex void vert( Attributes input, MotionVectorPassAttributes passInput, out PackedMotionVectorPassVaryings packedMvOutput, out PackedVaryings packedOutput) { Varyings output = (Varyings)0; MotionVectorPassVaryings mvOutput = (MotionVectorPassVaryings)0; MotionVectorPassOutput currentFrameMvData = (MotionVectorPassOutput)0; output = BuildVaryings(input, currentFrameMvData); packedOutput = PackVaryings(output); #if defined(HAVE_VFX_MODIFICATION) && !VFX_FEATURE_MOTION_VECTORS //Motion vector is enabled in SG but not active in VFX const bool forceNoMotion = true; #else const bool forceNoMotion = unity_MotionVectorsParams.y == 0.0; #endif if (!forceNoMotion) { #if defined(HAVE_VFX_MODIFICATION) float3 previousPositionOS = currentFrameMvData.vfxParticlePositionOS; #if defined(VFX_FEATURE_MOTION_VECTORS_VERTS) const bool applyDeformation = false; #else const bool applyDeformation = true; #endif #else const bool hasDeformation = unity_MotionVectorsParams.x == 1; // Mesh has skinned deformation float3 previousPositionOS = hasDeformation ? passInput.previousPositionOS : input.positionOS; #if defined(AUTOMATIC_TIME_BASED_MOTION_VECTORS) && defined(GRAPH_VERTEX_USES_TIME_PARAMETERS_INPUT) const bool applyDeformation = true; #else const bool applyDeformation = hasDeformation; #endif #endif #if defined(FEATURES_GRAPH_VERTEX) if (applyDeformation) previousPositionOS = GetLastFrameDeformedPosition(input, currentFrameMvData, previousPositionOS); else previousPositionOS = currentFrameMvData.positionOS; #if defined(FEATURES_GRAPH_VERTEX_MOTION_VECTOR_OUTPUT) previousPositionOS -= currentFrameMvData.motionVector; #endif #endif #if defined(UNITY_DOTS_INSTANCING_ENABLED) && defined(DOTS_DEFORMED) // Deformed vertices in DOTS are not cumulative with built-in Unity skinning/blend shapes // Needs to be called after vertex modification has been applied otherwise it will be // overwritten by Compute Deform node ApplyPreviousFrameDeformedVertexPosition(input.vertexID, previousPositionOS); #endif #if defined (_ADD_PRECOMPUTED_VELOCITY) previousPositionOS -= passInput.alembicMotionVectorOS; #endif mvOutput.positionCSNoJitter = mul(_NonJitteredViewProjMatrix, float4(currentFrameMvData.positionWS, 1.0f)); #if defined(HAVE_VFX_MODIFICATION) #if defined(VFX_FEATURE_MOTION_VECTORS_VERTS) #if defined(FEATURES_GRAPH_VERTEX_MOTION_VECTOR_OUTPUT) || defined(_ADD_PRECOMPUTED_VELOCITY) #error Unexpected fast path rendering VFX motion vector while there are vertex modification afterwards. #endif mvOutput.previousPositionCSNoJitter = VFXGetPreviousClipPosition(input, currentFrameMvData.vfxElementAttributes, mvOutput.positionCSNoJitter); #else #if VFX_WORLD_SPACE //previousPositionOS is already in world space const float3 previousPositionWS = previousPositionOS; #else const float3 previousPositionWS = mul(UNITY_PREV_MATRIX_M, float4(previousPositionOS, 1.0f)).xyz; #endif mvOutput.previousPositionCSNoJitter = mul(_PrevViewProjMatrix, float4(previousPositionWS, 1.0f)); #endif #else mvOutput.previousPositionCSNoJitter = mul(_PrevViewProjMatrix, mul(UNITY_PREV_MATRIX_M, float4(previousPositionOS, 1.0f))); #endif } packedMvOutput = PackMotionVectorVaryings(mvOutput); } // ------------------------------------- // Fragment float4 frag( // Note: packedMvInput needs to be before packedInput as otherwise we get the following error in the speed tree 8 SG: // "Non system-generated input signature parameter () cannot appear after a system generated value" PackedMotionVectorPassVaryings packedMvInput, PackedVaryings packedInput) : SV_Target { Varyings input = UnpackVaryings(packedInput); MotionVectorPassVaryings mvInput = UnpackMotionVectorVaryings(packedMvInput); UNITY_SETUP_INSTANCE_ID(input); SurfaceDescription surfaceDescription = BuildSurfaceDescription(input); #if defined(_ALPHATEST_ON) clip(surfaceDescription.Alpha - surfaceDescription.AlphaClipThreshold); #endif #if defined(LOD_FADE_CROSSFADE) && USE_UNITY_CROSSFADE LODFadeCrossFade(input.positionCS); #endif return float4(CalcNdcMotionVectorFromCsPositions(mvInput.positionCSNoJitter, mvInput.previousPositionCSNoJitter), 0, 0); } #endif