diff --git a/.github/actions/upload-dated-artifact/action.yaml b/.github/actions/upload-dated-artifact/action.yaml deleted file mode 100644 index 7fc3fbe..0000000 --- a/.github/actions/upload-dated-artifact/action.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: Upload dated artifact -description: Uploads an artifact with a datetime - -inputs: - name: - description: The name of the artifact - required: true - path: - description: The path to the file/folder to upload - required: true - -runs: - using: composite - steps: - # https://stackoverflow.com/questions/60942067/get-current-date-and-time-in-github-workflows - - name: Get current datetime - id: date - shell: bash - run: echo "::set-output name=date::$(date '+%Y-%m-%d_%H-%M-%S')" - - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: ${{ inputs.name }}_${{ steps.date.outputs.date }} - path: ${{ inputs.path }} - if-no-files-found: error diff --git a/.github/workflows/create-binaries.yaml b/.github/workflows/create-binaries.yaml deleted file mode 100644 index 26572bc..0000000 --- a/.github/workflows/create-binaries.yaml +++ /dev/null @@ -1,87 +0,0 @@ -name: Package using PyInstaller -on: - push: - tags: - - v** - workflow_dispatch: - -jobs: - build-windows: - env: - dist-path: dist/OpenSeeFace - runs-on: windows-latest - steps: - - name: Pull OpenSeeFace - uses: actions/checkout@v3 - - - name: Create binary - shell: cmd - run: | - choco install vcredist140 - - xcopy c:\Windows\System32\msvcp140.dll . - xcopy c:\Windows\System32\vcomp140.dll . - xcopy c:\Windows\System32\concrt140.dll . - xcopy c:\Windows\System32\vccorlib140.dll . - - make_exe.bat - - - name: Move files for uploading - shell: bash - run: | - # Prevents the parent dist/ directory from being included - mv dist/facetracker ${{ env.dist-path }} - cp -r models ${{ env.dist-path }} - - - name: Upload artifact - uses: ./.github/actions/upload-dated-artifact - with: - name: windows - path: dist # Add the parent directory to prevent a tarbomb - - # Files must be packed into a tar in order for file permissions to be preserved - build-unix: - env: - artifact-path: OpenSeeFace - tar-path: OpenSeeFace.tar - strategy: - fail-fast: false - matrix: - include: - - name: linux - os: ubuntu-latest - - name: mac - os: macos-latest - runs-on: ${{ matrix.os }} - steps: - - name: Pull OpenSeeFace - uses: actions/checkout@v3 - - - name: Create binary - shell: bash - run: | - chmod +x make_exe.sh - ./make_exe.sh - - - name: Move files for uploading - shell: bash - run: | - # Prevents the parent dist/ directory from being included - mv dist/facetracker ${{ env.artifact-path }} - cp -r models ${{ env.artifact-path }} - - - name: Fix permissions from PyInstaller - shell: bash - run: | - find ${{ env.artifact-path }} -type f -exec chmod -x {} + - chmod +x ${{ env.artifact-path }}/facetracker - - - name: Pack files into tar - shell: bash - run: tar -cvf ${{ env.tar-path }} ${{ env.artifact-path }} - - - name: Upload artifact - uses: ./.github/actions/upload-dated-artifact - with: - name: ${{ matrix.name }} - path: ${{ env.tar-path }} diff --git a/.gitignore b/.gitignore index afb12e9..aac297e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ Samples/* *.zip *.7z CSharp/* -VSeeFace/* \ No newline at end of file +OpenSeeDemo/* \ No newline at end of file diff --git a/Examples/Animations/JawOpen.anim b/Examples/Animations/JawOpen.anim deleted file mode 100644 index a726786..0000000 --- a/Examples/Animations/JawOpen.anim +++ /dev/null @@ -1,8243 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!74 &7400000 -AnimationClip: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: JawOpen - serializedVersion: 6 - m_Legacy: 0 - m_Compressed: 0 - m_UseHighQualityCurve: 1 - m_RotationCurves: [] - m_CompressedRotationCurves: [] - m_EulerCurves: [] - m_PositionCurves: [] - m_ScaleCurves: [] - m_FloatCurves: - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.5000001 - inSlope: 0 - outSlope: 60.00001 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.50000006 - inSlope: 60.00001 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootQ.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.50000006 - inSlope: 0 - outSlope: -59.999996 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.49999997 - inSlope: -59.999996 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootQ.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.50000006 - inSlope: 0 - outSlope: 59.999996 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.5 - inSlope: 59.999996 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootQ.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.5000001 - inSlope: 0 - outSlope: -60.00001 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.50000006 - inSlope: -60.00001 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootQ.w - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.042893473 - inSlope: 0 - outSlope: -0.0000026822088 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.04289343 - inSlope: -0.0000026822088 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootT.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -1.0000367 - inSlope: 0 - outSlope: 60.002228 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00000047683716 - inSlope: 60.002228 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootT.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.030454194 - inSlope: 0 - outSlope: 0.000007152557 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.030454075 - inSlope: 0.000007152557 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootT.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.5000002 - inSlope: 0 - outSlope: 60.00001 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.50000006 - inSlope: 60.00001 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootQ.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.5000001 - inSlope: 0 - outSlope: -60.000004 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.49999997 - inSlope: -60.000004 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootQ.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.5000001 - inSlope: 0 - outSlope: 60.000004 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.5 - inSlope: 60.000004 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootQ.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.50000006 - inSlope: 0 - outSlope: -59.999996 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.49999994 - inSlope: -59.999996 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootQ.w - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.046861146 - inSlope: 0 - outSlope: -0.0000026822088 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.04686119 - inSlope: -0.0000026822088 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootT.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -1.0000367 - inSlope: 0 - outSlope: 60.002228 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00000047683716 - inSlope: 60.002228 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootT.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.03045437 - inSlope: 0 - outSlope: 0.000007152557 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.03045425 - inSlope: 0.000007152557 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootT.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00004479574 - inSlope: 0 - outSlope: 0.0053791148 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00004485618 - inSlope: 0.0053791148 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandQ.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.041170064 - inSlope: 0 - outSlope: 4.9404073 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.041170064 - inSlope: 4.9404073 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandQ.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.001086921 - inSlope: 0 - outSlope: 0.13043165 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00108694 - inSlope: 0.13043165 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandQ.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.9991517 - inSlope: 0 - outSlope: -119.8982 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.9991517 - inSlope: -119.8982 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandQ.w - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.5371678 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.5371678 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandT.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.3336262 - inSlope: 0 - outSlope: 60.002228 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.3336633 - inSlope: 60.002228 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandT.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.01264843 - inSlope: 0 - outSlope: -0.0000024586914 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.012648389 - inSlope: -0.0000024586914 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandT.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.04116849 - inSlope: 0 - outSlope: -4.940218 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.04116848 - inSlope: -4.940218 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandQ.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000044902812 - inSlope: 0 - outSlope: -0.0053918567 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00004496147 - inSlope: -0.0053918567 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandQ.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.99915195 - inSlope: 0 - outSlope: -119.89822 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.99915177 - inSlope: -119.89822 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandQ.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0010898738 - inSlope: 0 - outSlope: 0.1307834 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.0010898496 - inSlope: 0.1307834 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandQ.w - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.5411321 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.5411321 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandT.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.333625 - inSlope: 0 - outSlope: 60.002235 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.3336623 - inSlope: 60.002235 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandT.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.012647478 - inSlope: 0 - outSlope: -0.0000023469327 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.012647439 - inSlope: -0.0000023469327 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandT.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000059604282 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000059604282 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootQ.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -5.972375e-10 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -5.972375e-10 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootQ.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000021520911 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000021520911 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootQ.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -1 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -1 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootQ.w - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: -0 - outSlope: 0.1441305 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootT.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1.0000372 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.0000372 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootT.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: -0 - outSlope: 0.12522256 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootT.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.8104302 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.8104302 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Little.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.8104303 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.8104303 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Little.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.4589378 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.4589378 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Little.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.66781396 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.66781396 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Little.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.8116108 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.8116108 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Ring.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.811611 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.811611 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Ring.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.62053007 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.62053007 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Ring.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6677725 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6677725 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Ring.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.81090564 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.81090564 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Middle.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.81090575 - inSlope: 0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.81090575 - inSlope: -0 - outSlope: 0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Middle.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.52660275 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.52660275 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Middle.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6681288 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6681288 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Middle.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.80583 - inSlope: 0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.80583 - inSlope: -0 - outSlope: 0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Index.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.8058302 - inSlope: 0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.8058302 - inSlope: -0 - outSlope: 0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Index.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.37857866 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.37857866 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Index.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.66687804 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.66687804 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Index.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6453491 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6453491 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Thumb.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6453488 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6453488 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Thumb.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.4428502 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.4428502 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Thumb.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.695377 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.695377 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Thumb.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.81042933 - inSlope: -0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.81042933 - inSlope: -0 - outSlope: -0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Little.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.81042975 - inSlope: -0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.81042975 - inSlope: -0 - outSlope: -0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Little.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.45892704 - inSlope: -0.0000017881392 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.45892704 - inSlope: -0 - outSlope: -0.0000017881392 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Little.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6678152 - inSlope: 0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6678152 - inSlope: -0 - outSlope: 0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Little.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.811611 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.811611 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Ring.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.811611 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.811611 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Ring.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.62051857 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.62051857 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Ring.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.66777277 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.66777277 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Ring.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.81090593 - inSlope: 0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.81090593 - inSlope: -0 - outSlope: 0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Middle.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.810906 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.810906 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Middle.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.52660847 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.52660847 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Middle.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.66812897 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.66812897 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Middle.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.80583125 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.80583125 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Index.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.80583125 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.80583125 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Index.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.37858424 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.37858424 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Index.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.66687816 - inSlope: -0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.66687816 - inSlope: -0 - outSlope: -0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Index.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6453328 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6453328 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Thumb.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.64533216 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.64533216 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Thumb.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.44295055 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.44295055 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Thumb.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.69563216 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.69563216 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Thumb.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000009919774 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000009919774 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Hand In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00034915068 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00034915068 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Hand Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.0085113235 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.0085113235 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Forearm Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1.0002763 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.0002763 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Forearm Stretch - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.0048716986 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.0048716986 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Arm Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.30338112 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.30338112 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Arm Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.39724782 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.39724782 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Arm Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -7.315273e-15 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -7.315273e-15 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Shoulder Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0000013660376 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.0000013660376 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Shoulder Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000009375498 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000009375498 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Hand In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00034944952 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00034944952 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Hand Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.00853448 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00853448 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Forearm Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1.0002779 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.0002779 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Forearm Stretch - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.004848006 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.004848006 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Arm Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.3033798 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.3033798 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Arm Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.39724767 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.39724767 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Arm Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Shoulder Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Shoulder Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000006830187 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000006830187 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Toes Up-Down - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.013827414 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.013827414 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Foot Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0016025845 - inSlope: 0.000000006984919 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.0016025845 - inSlope: -0 - outSlope: 0.000000006984919 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Foot Up-Down - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.11685848 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.11685848 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Lower Leg Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1.0034822 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.0034822 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Lower Leg Stretch - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.18365076 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.18365076 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Upper Leg Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.016341934 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.016341934 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Upper Leg In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.5968694 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.5968694 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Upper Leg Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000013660373 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000013660373 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Toes Up-Down - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0138261635 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.0138261635 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Foot Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0016021321 - inSlope: -0.000000006984919 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.0016021321 - inSlope: -0 - outSlope: -0.000000006984919 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Foot Up-Down - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.116853006 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.116853006 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Lower Leg Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1.0034825 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.0034825 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Lower Leg Stretch - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.18364348 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.18364348 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Upper Leg Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.016341235 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.016341235 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Upper Leg In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.59686947 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.59686947 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Upper Leg Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Jaw Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1 - inSlope: 0 - outSlope: -59.999996 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: -59.999996 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Jaw Close - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000021344334 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000021344334 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Eye In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000056918218 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000056918218 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Eye Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000026680409 - inSlope: -1.06581404e-13 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000026680409 - inSlope: -0 - outSlope: -1.06581404e-13 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Eye In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0000004268867 - inSlope: -1.7053025e-12 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.0000004268867 - inSlope: -0 - outSlope: -1.7053025e-12 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Eye Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000042688672 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000042688672 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Head Turn Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000034150938 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000034150938 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Head Tilt Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000042688665 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000042688665 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Head Nod Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.000000042688676 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.000000042688676 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Neck Turn Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.000000042688676 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.000000042688676 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Neck Tilt Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 6.3611073e-16 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 6.3611073e-16 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Neck Nod Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: UpperChest Twist Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: UpperChest Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000042688671 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000042688671 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: UpperChest Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000042688672 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000042688672 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Chest Twist Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000017075469 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000017075469 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Chest Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.000000042688672 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.000000042688672 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Chest Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.00000029882074 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00000029882074 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Spine Twist Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000008537731 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000008537731 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Spine Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000042688674 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000042688674 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Spine Front-Back - path: - classID: 95 - script: {fileID: 0} - m_PPtrCurves: [] - m_SampleRate: 60 - m_WrapMode: 0 - m_Bounds: - m_Center: {x: 0, y: 0, z: 0} - m_Extent: {x: 0, y: 0, z: 0} - m_ClipBindingConstant: - genericBindings: - - serializedVersion: 2 - path: 0 - attribute: 24 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 25 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 26 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 27 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 21 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 22 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 23 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 17 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 18 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 19 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 20 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 14 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 15 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 16 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 38 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 39 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 40 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 41 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 36 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 37 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 31 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 32 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 33 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 34 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 29 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 30 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 7 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 9 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 127 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 124 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 123 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 116 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 115 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 114 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 113 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 108 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 101 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 61 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 35 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 28 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 10 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 11 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 12 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 13 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 8 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 136 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 135 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 134 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 133 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 132 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 131 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 130 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 129 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 128 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 126 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 125 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 122 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 121 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 120 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 119 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 118 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 117 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 112 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 111 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 110 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 109 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 107 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 106 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 105 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 104 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 103 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 102 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 100 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 99 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 98 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 97 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 96 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 95 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 94 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 93 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 92 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 91 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 90 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 89 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 88 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 87 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 86 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 85 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 84 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 83 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 82 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 81 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 80 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 79 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 78 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 77 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 76 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 75 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 74 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 73 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 72 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 71 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 70 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 69 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 68 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 67 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 66 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 65 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 64 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 63 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 62 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 60 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 59 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 58 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 57 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 56 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 55 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 54 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 53 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 52 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 51 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 50 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 49 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 48 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 47 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 46 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 45 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 44 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 43 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 0 - attribute: 42 - script: {fileID: 0} - typeID: 95 - customType: 8 - isPPtrCurve: 0 - pptrCurveMapping: [] - m_AnimationClipSettings: - serializedVersion: 2 - m_AdditiveReferencePoseClip: {fileID: 0} - m_AdditiveReferencePoseTime: 0 - m_StartTime: 0 - m_StopTime: 0.016666668 - m_OrientationOffsetY: 0 - m_Level: 0 - m_CycleOffset: 0 - m_HasAdditiveReferencePose: 0 - m_LoopTime: 1 - m_LoopBlend: 0 - m_LoopBlendOrientation: 0 - m_LoopBlendPositionY: 0 - m_LoopBlendPositionXZ: 0 - m_KeepOriginalOrientation: 1 - m_KeepOriginalPositionY: 1 - m_KeepOriginalPositionXZ: 0 - m_HeightFromFeet: 0 - m_Mirror: 0 - m_EditorCurves: - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.5000001 - inSlope: 0 - outSlope: 60.00001 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.50000006 - inSlope: 60.00001 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootQ.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.50000006 - inSlope: 0 - outSlope: -59.999996 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.49999997 - inSlope: -59.999996 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootQ.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.50000006 - inSlope: 0 - outSlope: 59.999996 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.5 - inSlope: 59.999996 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootQ.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.5000001 - inSlope: 0 - outSlope: -60.00001 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.50000006 - inSlope: -60.00001 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootQ.w - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.042893473 - inSlope: 0 - outSlope: -0.0000026822088 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.04289343 - inSlope: -0.0000026822088 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootT.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -1.0000367 - inSlope: 0 - outSlope: 60.002228 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00000047683716 - inSlope: 60.002228 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootT.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.030454194 - inSlope: 0 - outSlope: 0.000007152557 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.030454075 - inSlope: 0.000007152557 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightFootT.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.5000002 - inSlope: 0 - outSlope: 60.00001 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.50000006 - inSlope: 60.00001 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootQ.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.5000001 - inSlope: 0 - outSlope: -60.000004 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.49999997 - inSlope: -60.000004 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootQ.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.5000001 - inSlope: 0 - outSlope: 60.000004 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.5 - inSlope: 60.000004 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootQ.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.50000006 - inSlope: 0 - outSlope: -59.999996 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.49999994 - inSlope: -59.999996 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootQ.w - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.046861146 - inSlope: 0 - outSlope: -0.0000026822088 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.04686119 - inSlope: -0.0000026822088 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootT.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -1.0000367 - inSlope: 0 - outSlope: 60.002228 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00000047683716 - inSlope: 60.002228 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootT.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.03045437 - inSlope: 0 - outSlope: 0.000007152557 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.03045425 - inSlope: 0.000007152557 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftFootT.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00004479574 - inSlope: 0 - outSlope: 0.0053791148 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00004485618 - inSlope: 0.0053791148 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandQ.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.041170064 - inSlope: 0 - outSlope: 4.9404073 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.041170064 - inSlope: 4.9404073 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandQ.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.001086921 - inSlope: 0 - outSlope: 0.13043165 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00108694 - inSlope: 0.13043165 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandQ.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.9991517 - inSlope: 0 - outSlope: -119.8982 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.9991517 - inSlope: -119.8982 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandQ.w - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.5371678 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.5371678 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandT.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.3336262 - inSlope: 0 - outSlope: 60.002228 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.3336633 - inSlope: 60.002228 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandT.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.01264843 - inSlope: 0 - outSlope: -0.0000024586914 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.012648389 - inSlope: -0.0000024586914 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHandT.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.04116849 - inSlope: 0 - outSlope: -4.940218 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.04116848 - inSlope: -4.940218 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandQ.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000044902812 - inSlope: 0 - outSlope: -0.0053918567 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00004496147 - inSlope: -0.0053918567 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandQ.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.99915195 - inSlope: 0 - outSlope: -119.89822 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.99915177 - inSlope: -119.89822 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandQ.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0010898738 - inSlope: 0 - outSlope: 0.1307834 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.0010898496 - inSlope: 0.1307834 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandQ.w - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.5411321 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.5411321 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandT.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.333625 - inSlope: 0 - outSlope: 60.002235 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.3336623 - inSlope: 60.002235 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandT.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.012647478 - inSlope: 0 - outSlope: -0.0000023469327 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.012647439 - inSlope: -0.0000023469327 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHandT.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000059604282 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000059604282 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootQ.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -5.972375e-10 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -5.972375e-10 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootQ.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000021520911 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000021520911 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootQ.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -1 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -1 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootQ.w - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: -0 - outSlope: 0.1441305 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootT.x - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1.0000372 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.0000372 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootT.y - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: -0 - outSlope: 0.12522256 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RootT.z - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.8104302 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.8104302 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Little.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.8104303 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.8104303 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Little.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.4589378 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.4589378 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Little.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.66781396 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.66781396 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Little.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.8116108 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.8116108 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Ring.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.811611 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.811611 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Ring.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.62053007 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.62053007 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Ring.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6677725 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6677725 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Ring.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.81090564 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.81090564 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Middle.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.81090575 - inSlope: 0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.81090575 - inSlope: -0 - outSlope: 0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Middle.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.52660275 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.52660275 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Middle.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6681288 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6681288 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Middle.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.80583 - inSlope: 0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.80583 - inSlope: -0 - outSlope: 0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Index.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.8058302 - inSlope: 0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.8058302 - inSlope: -0 - outSlope: 0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Index.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.37857866 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.37857866 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Index.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.66687804 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.66687804 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Index.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6453491 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6453491 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Thumb.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6453488 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6453488 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Thumb.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.4428502 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.4428502 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Thumb.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.695377 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.695377 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: RightHand.Thumb.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.81042933 - inSlope: -0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.81042933 - inSlope: -0 - outSlope: -0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Little.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.81042975 - inSlope: -0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.81042975 - inSlope: -0 - outSlope: -0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Little.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.45892704 - inSlope: -0.0000017881392 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.45892704 - inSlope: -0 - outSlope: -0.0000017881392 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Little.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6678152 - inSlope: 0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6678152 - inSlope: -0 - outSlope: 0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Little.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.811611 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.811611 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Ring.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.811611 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.811611 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Ring.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.62051857 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.62051857 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Ring.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.66777277 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.66777277 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Ring.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.81090593 - inSlope: 0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.81090593 - inSlope: -0 - outSlope: 0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Middle.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.810906 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.810906 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Middle.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.52660847 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.52660847 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Middle.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.66812897 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.66812897 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Middle.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.80583125 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.80583125 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Index.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.80583125 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.80583125 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Index.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.37858424 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.37858424 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Index.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.66687816 - inSlope: -0.0000035762785 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.66687816 - inSlope: -0 - outSlope: -0.0000035762785 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Index.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.6453328 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.6453328 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Thumb.3 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.64533216 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.64533216 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Thumb.2 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.44295055 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.44295055 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Thumb.Spread - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.69563216 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.69563216 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: LeftHand.Thumb.1 Stretched - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000009919774 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000009919774 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Hand In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00034915068 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00034915068 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Hand Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.0085113235 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.0085113235 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Forearm Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1.0002763 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.0002763 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Forearm Stretch - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.0048716986 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.0048716986 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Arm Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.30338112 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.30338112 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Arm Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.39724782 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.39724782 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Arm Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -7.315273e-15 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -7.315273e-15 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Shoulder Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0000013660376 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.0000013660376 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Shoulder Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000009375498 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000009375498 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Hand In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00034944952 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00034944952 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Hand Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.00853448 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00853448 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Forearm Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1.0002779 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.0002779 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Forearm Stretch - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.004848006 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.004848006 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Arm Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.3033798 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.3033798 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Arm Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.39724767 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.39724767 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Arm Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Shoulder Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Shoulder Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000006830187 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000006830187 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Toes Up-Down - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.013827414 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.013827414 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Foot Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0016025845 - inSlope: 0.000000006984919 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.0016025845 - inSlope: -0 - outSlope: 0.000000006984919 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Foot Up-Down - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.11685848 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.11685848 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Lower Leg Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1.0034822 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.0034822 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Lower Leg Stretch - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.18365076 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.18365076 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Upper Leg Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.016341934 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.016341934 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Upper Leg In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.5968694 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.5968694 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Upper Leg Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000013660373 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000013660373 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Toes Up-Down - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0138261635 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.0138261635 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Foot Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0016021321 - inSlope: -0.000000006984919 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.0016021321 - inSlope: -0 - outSlope: -0.000000006984919 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Foot Up-Down - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.116853006 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.116853006 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Lower Leg Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1.0034825 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 1.0034825 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Lower Leg Stretch - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.18364348 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.18364348 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Upper Leg Twist In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.016341235 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.016341235 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Upper Leg In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.59686947 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.59686947 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Upper Leg Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Jaw Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1 - inSlope: 0 - outSlope: -59.999996 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: -59.999996 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Jaw Close - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000021344334 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000021344334 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Eye In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000056918218 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000056918218 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Right Eye Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000026680409 - inSlope: -1.06581404e-13 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000026680409 - inSlope: -0 - outSlope: -1.06581404e-13 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Eye In-Out - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.0000004268867 - inSlope: -1.7053025e-12 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.0000004268867 - inSlope: -0 - outSlope: -1.7053025e-12 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Left Eye Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000042688672 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000042688672 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Head Turn Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000034150938 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000034150938 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Head Tilt Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000042688665 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000042688665 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Head Nod Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.000000042688676 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.000000042688676 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Neck Turn Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.000000042688676 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.000000042688676 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Neck Tilt Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 6.3611073e-16 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 6.3611073e-16 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Neck Nod Down-Up - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: UpperChest Twist Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: UpperChest Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000042688671 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000042688671 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: UpperChest Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.000000042688672 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.000000042688672 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Chest Twist Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000017075469 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000017075469 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Chest Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.000000042688672 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.000000042688672 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Chest Front-Back - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0.00000029882074 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: 0.00000029882074 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Spine Twist Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000008537731 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000008537731 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Spine Left-Right - path: - classID: 95 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: -0.00000042688674 - inSlope: 0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.016666668 - value: -0.00000042688674 - inSlope: -0 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: Spine Front-Back - path: - classID: 95 - script: {fileID: 0} - m_EulerEditorCurves: [] - m_HasGenericRootTransform: 0 - m_HasMotionFloatCurves: 0 - m_Events: [] diff --git a/Examples/Animations/JawOpen.anim.meta b/Examples/Animations/JawOpen.anim.meta deleted file mode 100644 index b5f5bf0..0000000 --- a/Examples/Animations/JawOpen.anim.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 697b139e69dcb414498dcd93210620ff -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Examples/OpenSeeVRMDriver.cs b/Examples/OpenSeeVRMDriver.cs index af2396d..44080cf 100644 --- a/Examples/OpenSeeVRMDriver.cs +++ b/Examples/OpenSeeVRMDriver.cs @@ -1,7 +1,3 @@ -#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN -#define WINDOWS_BUILD -#endif - using System; using System.Runtime.InteropServices; using System.Collections.Generic; @@ -10,18 +6,14 @@ using OpenSee; using VRM; // This is a more comprehensive VRM avatar animator than the OpenSeeVRMExpression example. -// To use the lip sync functionality, place the OVRLipSync 1.28 component somewhere in the scene. +// To use the lip sync functionality, place the OVRLipSync component somewhere in the scene. // No other OVR related components are required. public class OpenSeeVRMDriver : MonoBehaviour { - #if WINDOWS_BUILD #region DllImport [DllImport("user32.dll", SetLastError = true)] - static extern ushort GetAsyncKeyState(int vKey); + static extern ushort GetAsyncKeyState(int vKey); #endregion - #else - static ushort GetAsyncKeyState(int vKey) { return 0; } - #endif [Header("Settings")] [Tooltip("This is the OpenSeeExpression module used for expression prediction.")] @@ -30,20 +22,6 @@ public class OpenSeeVRMDriver : MonoBehaviour { public OpenSeeIKTarget openSeeIKTarget; [Tooltip("This is the target VRM avatar's blend shape proxy.")] public VRMBlendShapeProxy vrmBlendShapeProxy; - [Tooltip("When this is enabled, no blendshapes are set.")] - public bool skipApply = false; - [Tooltip("When this is enabled, no gaze tracking (bone or blendshape) is applied.")] - public bool skipApplyEyes = false; - [Tooltip("When this is enabled, no jaw bone animation is applied.")] - public bool skipApplyJaw = false; - [Tooltip("When this is enabled in addition to skipApply, expressions from hotkeys or expression detection are still applied.")] - public bool stillApplyExpressions = false; - [Tooltip("This factor is multiplied to all blendshape weights relating to camera tracking, as well as gaze and jaw tracking.")] - public float blendShapeWeight = 1f; - [Tooltip("This needs to be enabled when tracking with the fast 30 point model.")] - public bool only30Points = false; - [Tooltip("When enabled, if a model has perfect sync blendshapes, they will be used for more detailed tracking. (Experimental!)")] - public bool useCameraPerfectSync = false; //[Tooltip("When set to true, expression and audio data will be processed in FixedUpdate, otherwise it will be processed in Update.")] //public bool fixedUpdate = true; [Tooltip("When enabled, the avatar will blink automatically. Otherwise, blinks will be applied according to the face tracking's blink detection, allowing it to wink. Even for tracked eye blinks, the eye blink setting of the current expression is used.")] @@ -57,36 +35,12 @@ public class OpenSeeVRMDriver : MonoBehaviour { [Tooltip("This is the blink smoothing factor for camera based blink tracking, with 0 being no smoothing and 1 being a fixed blink state.")] [Range(0, 1)] public float blinkSmoothing = 0.75f; - [Tooltip("With tracked eye blinking, the eyes will close when looking down. Enable this to compensate this by modifying thresholds.")] - public bool lookDownCompensation = false; - [Tooltip("This is an angle value that can be used to adjust the angle from which a face is considered to be looking downwards.")] - [Range(-10, 20)] - public float lookDownAdjustment = 0f; - [Tooltip("When enabled, auto blinking will be enabled while looking down.")] - public bool autoBlinkLookingDown = false; - [Tooltip("When enabled, the blink state for both eyes is permanently linked together.")] - public bool linkBlinks = true; - [Tooltip("When enabled, it becomes possible to wink even with link blinks enabled.")] - public bool allowWinking = false; - [Tooltip("If allowWinking is enabled, if the eye blink values are within this distance, the blink is linked.")] - public float smartWinkThreshold = 0.85f; [Tooltip("When enabled, the avatar's eye will move according to the face tracker's gaze tracking.")] public bool gazeTracking = true; [Tooltip("This is the right eye bone. When either eye bone is not set, the VRM look direction blendshapes are used instead.")] public Transform rightEye; [Tooltip("This is the left eye bone. When either eye bone is not set, the VRM look direction blendshapes are used instead.")] public Transform leftEye; - [Tooltip("This is the eyebrow tracking strength, with 0 meaning no eyebrow tracking and 1 meaning full strength.")] - [Range(0, 1)] - public float eyebrowStrength = 1.0f; - [Tooltip("This is the eyebrow smoothing factor, with 0 being no smoothing and 1 being fixed eyebrows.")] - public float eyebrowSmoothing = 0.65f; - [Tooltip("This is the zero point of the eyebrow value. It can be used to offset the eyebrow tracking value.")] - [Range(-1, 1)] - public float eyebrowZero = 0.0f; - [Tooltip("This is the sensitivity of the eyebrow tracking, with 0 meaning no eyebrow movement.")] - [Range(0, 2)] - public float eyebrowSensitivity = 1.0f; [Tooltip("This is the gaze smoothing factor, with 0 being no smoothing and 1 being a fixed gaze.")] [Range(0, 1)] public float gazeSmoothing = 0.6f; @@ -98,36 +52,22 @@ public class OpenSeeVRMDriver : MonoBehaviour { [Tooltip("This factor is applied on top of the gazeFactor field.")] [Range(0, 5)] public float gazeStrength = 1f; - [Tooltip("This this adds an offset with values in the range of -1 to 1 to the gaze coordinates.")] - public Vector2 gazeCenter = Vector2.zero; [Tooltip("This component lets you customize the automatic eye blinking.")] public OpenSeeEyeBlink eyeBlinker = new OpenSeeEyeBlink(); - [Tooltip("When enabled, expressions will respond to global hotkeys.")] - public bool hotkeys = true; [Tooltip("This component lets configure your VRM expressions.")] public OpenSeeVRMExpression[] expressions = new OpenSeeVRMExpression[]{ - new OpenSeeVRMExpression("neutral", BlendShapePreset.Neutral, true, 1f, 1f, 1f, true, true, 0x70, true, true, false, true, 50f, 120f), - new OpenSeeVRMExpression("fun", BlendShapePreset.Fun, true, 1f, 1f, 1f, true, true, 0x71, true, true, false, true, 1f, 120f), - new OpenSeeVRMExpression("joy", BlendShapePreset.Joy, true, 1f, 1f, 1f, true, true, 0x72, true, true, false, true, 1f, 120f), - new OpenSeeVRMExpression("angry", BlendShapePreset.Angry, true, 1f, 1f, 0f, true, true, 0x73, true, true, false, true, 1f, 120f), - new OpenSeeVRMExpression("sorrow", BlendShapePreset.Sorrow, true, 1f, 1f, 0f, true, true, 0x74, true, true, false, true, 1f, 120f), - new OpenSeeVRMExpression("surprise", "Surprised", true, 1f, 1f, 0f, true, true, 0x75, true, true, false, true, 1f, 120f) + new OpenSeeVRMExpression("neutral", BlendShapePreset.Neutral, 1f, 1f, true, true, 0x70, 50f), + new OpenSeeVRMExpression("fun", BlendShapePreset.Fun, 1f, 1f, true, true, 0x71, 1f), + new OpenSeeVRMExpression("joy", BlendShapePreset.Joy, 1f, 1f, true, true, 0x72, 1f), + new OpenSeeVRMExpression("angry", BlendShapePreset.Angry, 1f, 1f, true, true, 0x73, 1f), + new OpenSeeVRMExpression("sorrow", BlendShapePreset.Sorrow, 1f, 1f, true, true, 0x74, 1f), + new OpenSeeVRMExpression("surprise", "Surprised", 1f, 1f, true, true, 0x75, 1f) }; [Tooltip("The expression configuration is initialized on startup. If it is changed and needs to be reinitialized, this can be triggered by using this flag or calling InitExpressionMap. This flag is reset to false afterwards.")] public bool reloadExpressions = false; [Header("Lip sync settings")] [Tooltip("This allows you to enable and disable lip sync. When disabled, mouth tracking is used instead.")] public bool lipSync = true; - [Tooltip("When enabled, camera based mouth tracking will be used when no viseme is detected.")] - public bool hybridLipSync = false; - [Tooltip("When enabled, viseme size will not depend on the OVR Lip Sync weight.")] - public bool maximizeLipSync = false; - [Tooltip("When enabled, mouth blendshapes are normalized if they add up to a value above 1.")] - public bool visemeNormalization = true; - [Tooltip("When enabled and the animator of the avatar has a float parameter called JawMovement, this parameter will be set to values from 0 to 1, corresponding to a closed to open mouth. This can be used for animating jaw bones.")] - public bool animateJawBone = false; - [Tooltip("This should be set to the included mecanim animation, which sets the jaw bone to closed on the first frame and to open on the second frame.")] - public AnimationClip jawBoneAnimation; [Tooltip("This is the mouth tracking smoothing factor, with 0 being no smoothing and 1 being a fixed mouth.")] [Range(0, 1)] public float mouthSmoothing = 0.6f; @@ -142,10 +82,8 @@ public class OpenSeeVRMDriver : MonoBehaviour { public float mouthSquelch = 0.01f; [Tooltip("With this, the squelch threshold above can be disabled.")] public bool mouthUseSquelch = false; - #if WINDOWS_BUILD [Tooltip("This allows you to select the OVRLipSync provider.")] public OVRLipSync.ContextProviders provider = OVRLipSync.ContextProviders.Enhanced; - #endif [Tooltip("When enabled, audio will be read from the given audio source, otherwise it will be read from the given mic.")] public bool useCanned = false; [Tooltip("This is the audio source for canned audio.")] @@ -154,12 +92,9 @@ public class OpenSeeVRMDriver : MonoBehaviour { public string mic = null; [Tooltip("When enabled, the lip sync function will be initialized or reinitialized in the next Update or FixedUpdate call, according to the IK target's fixedUpdate flag. This flag is reset to false afterwards. It is also possible to call InitializeLipSync instead.")] public bool initializeLipSync = false; - [Tooltip("This sets the viseme detection smoothing in a range from 1 to 100, where 1 means no smoothing and values above 90 mean pretty much no visemes.")] [Range(1, 100)] + [Tooltip("This sets the viseme smoothing in a range from 1 to 100, where 1 means no smoothing and values above 90 mean pretty much no visemes.")] public int smoothAmount = 50; - [Tooltip("This is the viseme animation smoothing factor, with 0 being no smoothing and 1 being no animation.")] - [Range(0, 1)] - public float visemeSmoothing = 0.75f; [Tooltip("Often, the A, I, U, E, O expressions are too strong, so you can scale them down using this value.")] [Range(0, 1)] public float visemeFactor = 0.6f; @@ -171,13 +106,7 @@ public class OpenSeeVRMDriver : MonoBehaviour { [Tooltip("This shows the current audio volume.")] public float audioVolume = 0f; - [HideInInspector] - public OpenSee.OpenSee.OpenSeeData openSeeData { get; private set; } = null; - - #if WINDOWS_BUILD private OVRLipSync.Frame visemeData = new OVRLipSync.Frame(); - #endif - private float fakeTimeTime = 0f; private float volume; static private bool inited = false; private int lastSmoothing = 50; @@ -193,406 +122,64 @@ public class OpenSeeVRMDriver : MonoBehaviour { private BlendShapeKey[] visemePresetMap; private Dictionary expressionMap; private OpenSeeVRMExpression currentExpression = null; - private OpenSeeVRMExpression lastExpression = null; - - private bool haveFullVisemeSet = false; - private BlendShapeKey[] fullVisemePresets; - #if WINDOWS_BUILD - private Dictionary ovrMap; - #endif - + private OpenSee.OpenSee.OpenSeeData openSeeData = null; + private float turnLeftBoundaryAngle = -30f; private float turnRightBoundaryAngle = 20f; - private float turnDownBoundaryAngle = 205f; - private float wasLookingDown = 0f; private double lastGaze = 0f; private float lastLookUpDown = 0f; private float lastLookLeftRight = 0f; private float currentLookUpDown = 0f; private float currentLookLeftRight = 0f; - private TimeInterpolate gazeInterpolate; + private int interpolationCount = 0; + private int interpolationState = 0; - private float[] lastVisemeValues; private double lastMouth = 0f; private float[] lastMouthStates; private float[] currentMouthStates; - private TimeInterpolate mouthInterpolate; - - private double startedSilVisemes = -10; - private double silVisemeHybridThreshold = 0.3; - private bool wasSilViseme = true; + private int mouthInterpolationCount = 0; + private int mouthInterpolationState = 0; private double lastBlink = 0f; private float lastBlinkLeft = 0f; private float lastBlinkRight = 0f; private float currentBlinkLeft = 0f; private float currentBlinkRight = 0f; - private TimeInterpolate blinkInterpolate; + private int blinkInterpolationCount = 0; + private int blinkInterpolationState = 0; private bool overridden = false; - private OpenSeeVRMExpression toggledExpression = null; - private HashSet continuedPress = new HashSet(); - private bool currentExpressionEnableBlinking; - private bool currentExpressionEnableVisemes; - private float currentExpressionEyebrowWeight; - private float currentExpressionVisemeFactor; - - private OpenSeeBlendShapeProxy proxy = null; - private Animator animator; - private bool haveJawParameter; - private Transform jawBone; - private Quaternion jawRotation = Quaternion.identity; - private HumanBodyBones[] humanBodyBones; - private Transform[] humanBodyBoneTransforms; - private Quaternion[] humanBodyBoneRotations; - - private VRMBlendShapeProxy lastAvatar = null; - private int eyebrowIsMoving = 0; - private double lastBrows = 0f; - private SkinnedMeshRenderer faceMesh; - private int faceType = -1; - private int browUpIndex = -1; - private int browDownIndex = -1; - private int browAngryIndex = -1; - private int browSorrowIndex = -1; - private float lastBrowUpDown = 0f; - private float[] lastBrowStates; - private float[] currentBrowStates; - private TimeInterpolate browInterpolate; - private BlendShapeKey[] browClips; - - private bool trackMouth = false; - private double lastPerfectSync = -1; - - private float lastAudioTime = -1f; + private int continuedPress = -1; - private class TimeInterpolate { - private float interpolateT = 0f; - private float updateT = 0f; - private double lastT = 0f; - private double currentT = 0f; - private float clamp = 1f; - private int gotData = 0; - - public TimeInterpolate() {} - public TimeInterpolate(float clamp) { - this.clamp = clamp; - } - - public void UpdateTime(double nowT) { - updateT = Time.time; - lastT = currentT; - currentT = nowT; - if (gotData < 2) - gotData++; - } - - public float Interpolate() { - interpolateT = Time.time; - if (interpolateT == updateT || gotData < 2) - return 0f; - return Mathf.Min((interpolateT - updateT) / (float)(currentT - lastT), clamp); - } - } - - // This class is used to ensure max() based instead of add() based blendshape accumulation and to allow setting animator parameters from blendshape values - private class OpenSeeBlendShapeProxy { - private HashSet browsBlendShapes = new HashSet() { "BROWS UP", "BROWS DOWN", "BROWINNERUP", "BROWDOWNLEFT", "BROWDOWNRIGHT", "BROWOUTERUPLEFT", "BROWOUTERUPRIGHT", "NOSESNEERLEFT", "NOSESNEERRIGHT" }; - private HashSet eyesBlendShapes = new HashSet() { "BLINK", "BLINK_L", "BLINK_R", "EYELOOKUPLEFT", "EYELOOKUPRIGHT", "EYELOOKDOWNLEFT", "EYELOOKDOWNRIGHT", "EYELOOKINLEFT", "EYELOOKINRIGHT", "EYELOOKOUTLEFT", "EYELOOKOUTRIGHT", "EYEBLINKLEFT", "EYEBLINKRIGHT", "EYESQUINTRIGHT", "EYESQUINTLEFT", "EYEWIDELEFT", "EYEWIDERIGHT", "NOSESNEERLEFT", "NOSESNEERRIGHT", "CHEEKSQUINTLEFT", "CHEEKSQUINTRIGHT" }; - private HashSet mouthBlendShapes = new HashSet() { "A", "I", "U", "E", "O", "SIL", "CH", "DD", "FF", "KK", "NN", "PP", "RR", "SS", "TH", "JAWOPEN", "JAWFORWARD", "JAWLEFT", "JAWRIGHT", "MOUTHFUNNEL", "MOUTHPUCKER", "MOUTHLEFT", "MOUTHRIGHT", "MOUTHROLLUPPER", "MOUTHROLLLOWER", "MOUTHSHRUGUPPER", "MOUTHSHRUGLOWER", "MOUTHCLOSE", "MOUTHSMILELEFT", "MOUTHSMILERIGHT", "MOUTHFROWNLEFT", "MOUTHFROWNRIGHT", "MOUTHDIMPLELEFT", "MOUTHDIMPLERIGHT", "MOUTHUPPERUPLEFT", "MOUTHUPPERUPRIGHT", "MOUTHLOWERDOWNLEFT", "MOUTHLOWERDOWNRIGHT", "MOUTHPRESSLEFT", "MOUTHPRESSRIGHT", "MOUTHSTRETCHLEFT", "MOUTHSTRETCHRIGHT", "TONGUEOUT", "CHEEKSQUINTLEFT", "CHEEKSQUINTRIGHT" }; - private bool clearPSBrows = false; - private bool clearPSEyes = false; - private bool clearPSMouth = false; - private Dictionary clearKeys = new Dictionary(); - - private bool perfectSync = false; - private HashSet visemeBlendShapes = new HashSet() { "A", "I", "U", "E", "O", "SIL", "CH", "DD", "FF", "KK", "NN", "PP", "RR", "SS", "TH" }; - private string[] perfectSyncNames = new string[] { "BROWINNERUP", "BROWDOWNLEFT", "BROWDOWNRIGHT", "BROWOUTERUPLEFT", "BROWOUTERUPRIGHT", "EYELOOKUPLEFT", "EYELOOKUPRIGHT", "EYELOOKDOWNLEFT", "EYELOOKDOWNRIGHT", "EYELOOKINLEFT", "EYELOOKINRIGHT", "EYELOOKOUTLEFT", "EYELOOKOUTRIGHT", "EYEBLINKLEFT", "EYEBLINKRIGHT", "EYESQUINTRIGHT", "EYESQUINTLEFT", "EYEWIDELEFT", "EYEWIDERIGHT", "CHEEKPUFF", "CHEEKSQUINTLEFT", "CHEEKSQUINTRIGHT", "NOSESNEERLEFT", "NOSESNEERRIGHT", "JAWOPEN", "JAWFORWARD", "JAWLEFT", "JAWRIGHT", "MOUTHFUNNEL", "MOUTHPUCKER", "MOUTHLEFT", "MOUTHRIGHT", "MOUTHROLLUPPER", "MOUTHROLLLOWER", "MOUTHSHRUGUPPER", "MOUTHSHRUGLOWER", "MOUTHCLOSE", "MOUTHSMILELEFT", "MOUTHSMILERIGHT", "MOUTHFROWNLEFT", "MOUTHFROWNRIGHT", "MOUTHDIMPLELEFT", "MOUTHDIMPLERIGHT", "MOUTHUPPERUPLEFT", "MOUTHUPPERUPRIGHT", "MOUTHLOWERDOWNLEFT", "MOUTHLOWERDOWNRIGHT", "MOUTHPRESSLEFT", "MOUTHPRESSRIGHT", "MOUTHSTRETCHLEFT", "MOUTHSTRETCHRIGHT", "TONGUEOUT" }; - private InterpolatedMap perfectSyncMap = new InterpolatedMap(); - private Dictionary clipMap = new Dictionary(); - - private VRMBlendShapeProxy proxy = null; - private Animator animator = null; - private RuntimeAnimatorController animatorController = null; - private Dictionary clearMap = new Dictionary(); - private Dictionary values = new Dictionary(); - private Dictionary clipNames = new Dictionary(); - private Dictionary> parameters = new Dictionary>(); - private bool interpolatedPerfectSync = false; - private float defaultWeight = 1f; - private OpenSeeVRMDriver vrmDriver = null; - - public OpenSeeBlendShapeProxy(OpenSeeVRMDriver vrmDriver) { - this.vrmDriver = vrmDriver; - } - - void InterpolatePerfectSync() { - if (!HasPerfectSync() || interpolatedPerfectSync) - return; - foreach (var name in perfectSyncNames) { - if (!perfectSyncMap.Check(name)) - continue; - float weight = perfectSyncMap.Get(name); - AccumulateValue(name, weight, 1f); - } - interpolatedPerfectSync = true; - } - - public void ClearPerfectSync() { - perfectSyncMap.Clear(); - } - - public void SetPerfectSync(string name, float weight, double nowT, float factor) { - perfectSyncMap.Store(name.ToUpper(), Mathf.Clamp(weight * factor, 0f, 1f), nowT); - } - - public void SetPerfectSync(string name, float weight, double nowT) { - SetPerfectSync(name, weight, nowT, defaultWeight); - } - - public bool HasPerfectSync() { - if (proxy == null || animator == null) - return false; - return perfectSync; - } - - public void SetWeight(float v) { - defaultWeight = v; - } - - public void DisableFaceParts(bool brows, bool eyes, bool mouth) { - clearPSBrows = brows; - clearPSEyes = eyes; - clearPSMouth = mouth; - } - - private void SetFloat(BlendShapeKey key, float weight) { - SetFloat(key, weight, defaultWeight); - } - - private void SetFloat(BlendShapeKey key, float weight, float factor) { - if (!clipNames.ContainsKey(key)) - return; - string name = clipNames[key]; - weight *= factor; - if (animator != null && parameters.ContainsKey(name)) { - var parameter = parameters[name]; - if (parameter.Item2 == AnimatorControllerParameterType.Float) - animator.SetFloat(parameter.Item1, weight); - if (parameter.Item2 == AnimatorControllerParameterType.Bool) - animator.SetBool(parameter.Item1, weight > 0.5f); - } - } - - private void CheckAnimatorController() { - if (animator == null) - return; - if (animatorController != animator.runtimeAnimatorController) { - animatorController = animator.runtimeAnimatorController; - parameters.Clear(); - foreach (var parameter in animator.parameters) { - string key = parameter.name.ToUpper(); - if (!parameters.ContainsKey(key) && (parameter.type == AnimatorControllerParameterType.Float || parameter.type == AnimatorControllerParameterType.Bool)) - parameters.Add(key, new Tuple(parameter.name, parameter.type)); - else - parameters[key] = new Tuple(parameter.name, parameter.type); - } - } - } - - public void Clear() { - CheckAnimatorController(); - interpolatedPerfectSync = false; - if (proxy != null) { - foreach (var pair in proxy.GetValues()) { - SetFloat(pair.Key, 0f); - } - foreach (var pair in values) { - SetFloat(pair.Key, 0f); - } - proxy.SetValues(clearMap); - } - values.Clear(); - } - - void NormalizeVisemes() { - float total = 0f; - foreach (var pair in values) { - string name = pair.Key.Name.ToUpper(); - if (visemeBlendShapes.Contains(name)) - total += pair.Value; - } - if (total > 1f) { - var keys = new List(values.Keys); - foreach (var key in keys) { - string name = key.Name.ToUpper(); - if (visemeBlendShapes.Contains(name)) - values[key] = values[key] / total; - } - } - } - - public void Apply() { - if (proxy == null) - return; - CheckAnimatorController(); - if (perfectSync) - InterpolatePerfectSync(); - if (vrmDriver != null && vrmDriver.visemeNormalization) - NormalizeVisemes(); - if (clearPSBrows || clearPSEyes || clearPSMouth) { - clearKeys.Clear(); - foreach (var pair in proxy.GetValues()) { - string name = pair.Key.Name.ToUpper(); - if (clearPSBrows && browsBlendShapes.Contains(name)) { - clearKeys[pair.Key] = 0f; - values[pair.Key] = 0f; - } else if (clearPSEyes && eyesBlendShapes.Contains(name)) { - clearKeys[pair.Key] = 0f; - values[pair.Key] = 0f; - } else if (clearPSMouth && mouthBlendShapes.Contains(name)) { - clearKeys[pair.Key] = 0f; - values[pair.Key] = 0f; - } - } - clearPSBrows = false; - clearPSEyes = false; - clearPSMouth = false; - } - proxy.SetValues(values); - foreach (var pair in values) { - SetFloat(pair.Key, pair.Value, 1f); - } - proxy.Apply(); - } - - public void AccumulateValue(BlendShapeKey key, float weight, float factor) { - if (!values.ContainsKey(key)) - values.Add(key, weight * factor); - else - values[key] = Mathf.Max(values[key], weight * factor); - } - - public void AccumulateValue(BlendShapeKey key, float weight) { - AccumulateValue(key, weight, defaultWeight); - } - - public void AccumulateValue(string key, float weight, float factor) { - if (!clipMap.ContainsKey(key.ToUpper())) - return; - AccumulateValue(clipMap[key.ToUpper()], weight, factor); - } - - public void AccumulateValue(string key, float weight) { - AccumulateValue(key, weight, defaultWeight); - } - - public void UpdateAvatar(VRMBlendShapeProxy vrmBlendShapeProxy, Animator animator) { - proxy = vrmBlendShapeProxy; - this.animator = animator; - - perfectSync = false; - if (proxy == null) - return; - HashSet perfectSyncSet = new HashSet(perfectSyncNames); - clipMap.Clear(); - clipNames.Clear(); - clearMap.Clear(); - perfectSyncMap.Clear(); - //perfectSyncMap.SetSmoothing(0.5f); - foreach (BlendShapeClip clip in vrmBlendShapeProxy.BlendShapeAvatar.Clips) { - if (clip.Preset == BlendShapePreset.Unknown && clip.BlendShapeName != null) { - string name = clip.BlendShapeName.ToUpper(); - clipMap.Add(name, BlendShapeKey.CreateUnknown(clip.BlendShapeName)); - clipNames.Add(BlendShapeKey.CreateUnknown(clip.BlendShapeName), name); - clearMap.Add(BlendShapeKey.CreateUnknown(clip.BlendShapeName), 0f); - if (perfectSyncSet.Contains(name)) { - perfectSyncSet.Remove(name); - } - } else if (clip.Preset != BlendShapePreset.Unknown) { - string name = clip.BlendShapeName.ToUpper(); - clipNames.Add(BlendShapeKey.CreateFromPreset(clip.Preset), name); - clearMap.Add(BlendShapeKey.CreateFromPreset(clip.Preset), 0f); - } - } - if (perfectSyncSet.Count < 1) - perfectSync = true; - } - } - - #if WINDOWS_BUILD private Dictionary catsData = null; - #endif void InitCatsData() { - #if WINDOWS_BUILD catsData = new Dictionary(); - // This is similar to what the Blender CATS plugin does, but with A, I, U, E, O, JawOpen - catsData.Add(OVRLipSync.Viseme.sil, new float[]{0f, 0f, 0f, 0f, 0f, 0f}); - catsData.Add(OVRLipSync.Viseme.aa, new float[]{0.9998f, 0f, 0f, 0f, 0f, 1f}); - catsData.Add(OVRLipSync.Viseme.CH, new float[]{0f, 0.9996f, 0f, 0f, 0f, 1f}); - catsData.Add(OVRLipSync.Viseme.DD, new float[]{0.3f, 0.7f, 0f, 0f, 0f, 0.7f}); - catsData.Add(OVRLipSync.Viseme.E, new float[]{0f, 0f, 0f, 0.9997f, 0f, 0.6f}); - catsData.Add(OVRLipSync.Viseme.FF, new float[]{0.2f, 0.4f, 0f, 0f, 0f, 0.1f}); - catsData.Add(OVRLipSync.Viseme.ih, new float[]{0.5f, 0.2f, 0f, 0f, 0f, 0.5f}); - catsData.Add(OVRLipSync.Viseme.kk, new float[]{0.7f, 0.4f, 0f, 0f, 0f, 0.0f}); - catsData.Add(OVRLipSync.Viseme.nn, new float[]{0.2f, 0.7f, 0f, 0f, 0f, 0.1f}); - catsData.Add(OVRLipSync.Viseme.oh, new float[]{0f, 0f, 0f, 0f, 0.9999f, 1f}); - catsData.Add(OVRLipSync.Viseme.ou, new float[]{0f, 0f, 0.9995f, 0f, 0f, 1f}); - catsData.Add(OVRLipSync.Viseme.PP, new float[]{0.4f, 0f, 0f, 0f, 0.4f, 0f}); - catsData.Add(OVRLipSync.Viseme.RR, new float[]{0f, 0.5f, 0f, 0f, 0.3f, 0.4f}); - catsData.Add(OVRLipSync.Viseme.SS, new float[]{0f, 0.8f, 0f, 0f, 0f, 0.3f}); - catsData.Add(OVRLipSync.Viseme.TH, new float[]{0.4f, 0f, 0f, 0f, 0.15f, 0.5f}); - #endif - visemePresetMap = new BlendShapeKey[6] { - BlendShapeKey.CreateFromPreset(BlendShapePreset.A), - BlendShapeKey.CreateFromPreset(BlendShapePreset.I), - BlendShapeKey.CreateFromPreset(BlendShapePreset.U), - BlendShapeKey.CreateFromPreset(BlendShapePreset.E), - BlendShapeKey.CreateFromPreset(BlendShapePreset.O), - BlendShapeKey.CreateFromPreset(BlendShapePreset.Unknown) - }; - lastVisemeValues = new float[] {0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f}; - #if WINDOWS_BUILD - ovrMap = new Dictionary() { - [OVRLipSync.Viseme.sil] = 0, - [OVRLipSync.Viseme.aa] = 1, - [OVRLipSync.Viseme.CH] = 2, - [OVRLipSync.Viseme.DD] = 3, - [OVRLipSync.Viseme.E] = 4, - [OVRLipSync.Viseme.FF] = 5, - [OVRLipSync.Viseme.ih] = 6, - [OVRLipSync.Viseme.kk] = 7, - [OVRLipSync.Viseme.nn] = 8, - [OVRLipSync.Viseme.oh] = 9, - [OVRLipSync.Viseme.ou] = 10, - [OVRLipSync.Viseme.PP] = 11, - [OVRLipSync.Viseme.RR] = 12, - [OVRLipSync.Viseme.SS] = 13, - [OVRLipSync.Viseme.TH] = 14 - }; - #endif - fullVisemePresets = new BlendShapeKey[16] { - BlendShapeKey.CreateUnknown("SIL"), - BlendShapeKey.CreateFromPreset(BlendShapePreset.A), - BlendShapeKey.CreateUnknown("CH"), - BlendShapeKey.CreateUnknown("DD"), - BlendShapeKey.CreateFromPreset(BlendShapePreset.E), - BlendShapeKey.CreateUnknown("FF"), - BlendShapeKey.CreateFromPreset(BlendShapePreset.I), - BlendShapeKey.CreateUnknown("KK"), - BlendShapeKey.CreateUnknown("NN"), - BlendShapeKey.CreateFromPreset(BlendShapePreset.O), - BlendShapeKey.CreateFromPreset(BlendShapePreset.U), - BlendShapeKey.CreateUnknown("PP"), - BlendShapeKey.CreateUnknown("RR"), - BlendShapeKey.CreateUnknown("SS"), - BlendShapeKey.CreateUnknown("TH"), - BlendShapeKey.CreateFromPreset(BlendShapePreset.Unknown) + // This is similar to what the Blender CATS plugin does, but with A, I, U, E, O + catsData.Add(OVRLipSync.Viseme.sil, new float[]{0f, 0f, 0f, 0f, 0f}); + catsData.Add(OVRLipSync.Viseme.aa, new float[]{0.9998f, 0f, 0f, 0f, 0f}); + catsData.Add(OVRLipSync.Viseme.CH, new float[]{0f, 0.9996f, 0f, 0f, 0f}); + catsData.Add(OVRLipSync.Viseme.DD, new float[]{0.3f, 0.7f, 0f, 0f, 0f}); + catsData.Add(OVRLipSync.Viseme.E, new float[]{0f, 0f, 0f, 0.9997f, 0f}); + catsData.Add(OVRLipSync.Viseme.FF, new float[]{0.2f, 0.4f, 0f, 0f, 0f}); + catsData.Add(OVRLipSync.Viseme.ih, new float[]{0.5f, 0.2f, 0f, 0f, 0f}); + catsData.Add(OVRLipSync.Viseme.kk, new float[]{0.7f, 0.4f, 0f, 0f, 0f}); + catsData.Add(OVRLipSync.Viseme.nn, new float[]{0.2f, 0.7f, 0f, 0f, 0f}); + catsData.Add(OVRLipSync.Viseme.oh, new float[]{0f, 0f, 0f, 0f, 0.9999f}); + catsData.Add(OVRLipSync.Viseme.ou, new float[]{0f, 0f, 0.9995f, 0f, 0f}); + catsData.Add(OVRLipSync.Viseme.PP, new float[]{0.4f, 0f, 0f, 0f, 0.4f}); + catsData.Add(OVRLipSync.Viseme.RR, new float[]{0f, 0.5f, 0f, 0f, 0.3f}); + catsData.Add(OVRLipSync.Viseme.SS, new float[]{0f, 0.8f, 0f, 0f, 0f}); + catsData.Add(OVRLipSync.Viseme.TH, new float[]{0.4f, 0f, 0f, 0f, 0.15f}); + visemePresetMap = new BlendShapeKey[5] { + new BlendShapeKey(BlendShapePreset.A), + new BlendShapeKey(BlendShapePreset.I), + new BlendShapeKey(BlendShapePreset.U), + new BlendShapeKey(BlendShapePreset.E), + new BlendShapeKey(BlendShapePreset.O) }; } - #if WINDOWS_BUILD OVRLipSync.Viseme GetActiveViseme(out float bestValue) { var visemes = Enum.GetValues(typeof(OVRLipSync.Viseme)); bestValue = -1f; @@ -605,145 +192,44 @@ public class OpenSeeVRMDriver : MonoBehaviour { } return bestViseme; } - #endif - - bool ApplyVisemes() { - #if WINDOWS_BUILD - trackMouth = false; + + void ApplyVisemes() { if (vrmBlendShapeProxy == null || catsData == null) - return true; + return; float expressionFactor = 1f; if (currentExpression != null) - expressionFactor = currentExpressionVisemeFactor; - if (currentExpression != null && !currentExpressionEnableVisemes) { - return true; + expressionFactor = currentExpression.visemeFactor; + if (currentExpression != null && !currentExpression.enableVisemes) { + for (int i = 0; i < 5; i++) { + vrmBlendShapeProxy.ImmediatelySetValue(visemePresetMap[i], 0f); + } + return; } float weight; OVRLipSync.Viseme current = GetActiveViseme(out weight); - if (current == OVRLipSync.Viseme.sil) { - if (wasSilViseme) { - if (hybridLipSync && Time.time - startedSilVisemes > silVisemeHybridThreshold) { - ApplyMouthShape(); - return false; - } - } else { - startedSilVisemes = Time.time; - } - wasSilViseme = true; - } else { - if (wasSilViseme) - startedSilVisemes = Time.time; - wasSilViseme = false; - if (hybridLipSync && Time.time - startedSilVisemes < silVisemeHybridThreshold) - ApplyMouthShape(true); - } - if (!maximizeLipSync) - weight = Mathf.Clamp(weight * 1.5f, 0f, 1f); - else - weight = 1f; - - float[] values = new float[16]; - int lastIdx = 5; - if (haveFullVisemeSet) { - lastIdx = 15; - values[ovrMap[current]] = weight; - values[lastIdx] = catsData[current][5]; - } else { - Array.Copy(catsData[current], values, 6); - } - - for (int i = 0; i <= lastIdx; i++) { - lastVisemeValues[i] = values[i] * weight * (1f - visemeSmoothing) + lastVisemeValues[i] * visemeSmoothing; - if (lastVisemeValues[i] < 0f) { - lastVisemeValues[i] = 0f; - } - if (lastVisemeValues[i] > 1f) { - lastVisemeValues[i] = 1f; - } - float result = lastVisemeValues[i] * visemeFactor * expressionFactor; - if (result > 0f && i < lastIdx) { - if (haveFullVisemeSet) - proxy.AccumulateValue(fullVisemePresets[i], result, 1f); - else - proxy.AccumulateValue(visemePresetMap[i], result, 1f); - } - if (i == lastIdx) { - if (animateJawBone) - SetJaw(result * 0.99999f); - else - SetJaw(0f); - } - } - #endif - return false; - } - - void SetJaw(float v) { - if (haveJawParameter) { - animator.SetFloat("JawMovement", v); - return; - } - if (jawBoneAnimation != null && jawBone != null) { - for (int i = 0; i < humanBodyBones.Length; i++) { - if (humanBodyBoneTransforms[i] != null) - humanBodyBoneRotations[i] = humanBodyBoneTransforms[i].localRotation; - } - jawBoneAnimation.SampleAnimation(lastAvatar.gameObject, v / jawBoneAnimation.frameRate); - jawRotation = jawBone.localRotation; - for (int i = 0; i < humanBodyBones.Length; i++) { - if (humanBodyBoneTransforms[i] != null) - humanBodyBoneTransforms[i].localRotation = humanBodyBoneRotations[i]; - } - return; + weight = Mathf.Clamp(weight * 1.5f, 0f, 1f); + float[] values = catsData[current]; + for (int i = 0; i < 5; i++) { + vrmBlendShapeProxy.ImmediatelySetValue(visemePresetMap[i], values[i] * visemeFactor * expressionFactor * weight); } } - void ApplyMouthShape(bool fadeOnly) { + void ApplyMouthShape() { if (vrmBlendShapeProxy == null) return; if (visemePresetMap == null) InitCatsData(); + for (int i = 0; i < 5; i++) { + vrmBlendShapeProxy.ImmediatelySetValue(visemePresetMap[i], 0f); + } if (openSeeData == null || openSeeData.features == null) return; - if (lastMouthStates == null) - lastMouthStates = new float[]{0f, 0f, 0f, 0f, 0f, 0f}; - if (currentMouthStates == null) - currentMouthStates = new float[]{0f, 0f, 0f, 0f, 0f, 0f}; - - if (mouthInterpolate == null) - mouthInterpolate = new TimeInterpolate(); - float t = mouthInterpolate.Interpolate(); - - if (currentExpression != null && !currentExpressionEnableVisemes) - return; - - trackMouth = !fadeOnly; - - float expressionFactor = 1f; - if (currentExpression != null) - expressionFactor = currentExpressionVisemeFactor; - - for (int i = 0; i < 6; i++) { - float interpolated = Mathf.Lerp(lastMouthStates[i], currentMouthStates[i], t); - float result = interpolated * expressionFactor * visemeFactor; - if (i < 5 && result > 0f) - if (!useCameraPerfectSync || !proxy.HasPerfectSync()) - proxy.AccumulateValue(visemePresetMap[i], result); - if (i == 5) { - if (animateJawBone) - SetJaw(result * 0.99999f * blendShapeWeight); - else - SetJaw(0f); - } - } - if (lastMouth < openSeeData.time) { lastMouth = openSeeData.time; - mouthInterpolate.UpdateTime(lastMouth); float open = openSeeData.features.MouthOpen; float wide = openSeeData.features.MouthWide; - float[] mouthStates = new float[]{0f, 0f, 0f, 0f, 0f, 0f}; + float[] mouthStates = new float[]{0f, 0f, 0f, 0f, 0f}; float stabilizer = mouthStabilizer; float stabilizerWide = mouthStabilizerWide; @@ -753,11 +239,8 @@ public class OpenSeeVRMDriver : MonoBehaviour { } do { - if (fadeOnly) - break; if (mouthUseSquelch && audioVolume < mouthSquelch) break; - mouthStates[5] = Mathf.Clamp(open / 0.55f - 0.1f, 0f, 1f); if (open < stabilizer && Mathf.Abs(wide) < stabilizer) break; if (wide > stabilizer && open < stabilizerWide) @@ -767,7 +250,7 @@ public class OpenSeeVRMDriver : MonoBehaviour { mouthStates[4] = open; } else if (open >= 0f) { // A - mouthStates[0] = open; + mouthStates[0] = open * 1f; } if (wide >= 0f && open > stabilizer * 0.5f) { if (wide > 0.5f) { @@ -775,7 +258,7 @@ public class OpenSeeVRMDriver : MonoBehaviour { mouthStates[1] = wide; } else { // E - mouthStates[3] = wide; + mouthStates[3] = wide * 1f; } } else if (wide < Mathf.Clamp(stabilizerWide * 1.5f, 0f, 0.8f) && open > stabilizer) { // U @@ -796,363 +279,35 @@ public class OpenSeeVRMDriver : MonoBehaviour { } } while (false); - for (int i = 0; i < 6; i++) { - lastMouthStates[i] = Mathf.Lerp(lastMouthStates[i], currentMouthStates[i], t); - mouthStates[i] = Mathf.Lerp(lastMouthStates[i], mouthStates[i], 1f - mouthSmoothing); + if (mouthInterpolationState == 2) { + for (int i = 0; i < 5; i++) { + mouthStates[i] = Mathf.Lerp(currentMouthStates[i], mouthStates[i], 1f - mouthSmoothing); + } } + + lastMouthStates = currentMouthStates; currentMouthStates = mouthStates; + if (mouthInterpolationState < 2) + mouthInterpolationState++; + mouthInterpolationCount = 0; } - } - - void ApplyMouthShape() { - ApplyMouthShape(false); - } - - void UpdatePerfectSync() { - if (openSeeData == null || lastPerfectSync >= openSeeData.time) + + if (mouthInterpolationState < 2) return; - lastPerfectSync = openSeeData.time; - if (useCameraPerfectSync && proxy.HasPerfectSync()) { - float upDownStrength = (openSeeData.features.EyebrowUpDownLeft + openSeeData.features.EyebrowUpDownRight) / 2f; - if (upDownStrength > 0f) - proxy.SetPerfectSync("BROWINNERUP", upDownStrength * 0.8f, lastPerfectSync); - else - proxy.SetPerfectSync("BROWINNERUP", 0, lastPerfectSync); - - if (openSeeData.features.EyebrowUpDownLeft < 0.2f) { - proxy.SetPerfectSync("BROWDOWNLEFT", -openSeeData.features.EyebrowUpDownLeft * 0.5f, lastPerfectSync); - if (openSeeData.features.EyeLeft < 0.1f && openSeeData.features.EyeLeft > -0.6f) { - proxy.SetPerfectSync("EYESQUINTLEFT", -openSeeData.features.EyeLeft, lastPerfectSync); - proxy.SetPerfectSync("EYEBLINKLEFT", 0, lastPerfectSync); - } else if (openSeeData.features.EyeLeft <= -0.6f) { - proxy.SetPerfectSync("EYEBLINKLEFT", -openSeeData.features.EyeLeft * 1.5f, lastPerfectSync); - proxy.SetPerfectSync("EYESQUINTLEFT", 0, lastPerfectSync); - } else { - proxy.SetPerfectSync("EYESQUINTLEFT", 0, lastPerfectSync); - proxy.SetPerfectSync("EYEBLINKLEFT", 0, lastPerfectSync); - } - } else { - proxy.SetPerfectSync("BROWDOWNLEFT", 0, lastPerfectSync); - proxy.SetPerfectSync("EYESQUINTLEFT", 0, lastPerfectSync); - if (openSeeData.features.EyeLeft <= -0.3f) - proxy.SetPerfectSync("EYEBLINKLEFT", -openSeeData.features.EyeLeft * 1.5f, lastPerfectSync); - else - proxy.SetPerfectSync("EYEBLINKLEFT", 0, lastPerfectSync); - } - - if (openSeeData.features.EyebrowUpDownRight < 0.2f) { - proxy.SetPerfectSync("BROWDOWNRIGHT", -openSeeData.features.EyebrowUpDownRight * 0.5f, lastPerfectSync); - if (openSeeData.features.EyeRight < 0.1f && openSeeData.features.EyeRight > -0.6f) { - proxy.SetPerfectSync("EYESQUINTRIGHT", -openSeeData.features.EyeRight, lastPerfectSync); - proxy.SetPerfectSync("EYEBLINKRIGHT", 0, lastPerfectSync); - } else if (openSeeData.features.EyeRight <= -0.6f) { - proxy.SetPerfectSync("EYEBLINKRIGHT", -openSeeData.features.EyeRight * 1.5f, lastPerfectSync); - proxy.SetPerfectSync("EYESQUINTRIGHT", 0, lastPerfectSync); - } else { - proxy.SetPerfectSync("EYESQUINTRIGHT", 0, lastPerfectSync); - proxy.SetPerfectSync("EYEBLINKRIGHT", 0, lastPerfectSync); - } - } else { - proxy.SetPerfectSync("BROWDOWNRIGHT", 0, lastPerfectSync); - proxy.SetPerfectSync("EYESQUINTRIGHT", 0, lastPerfectSync); - if (openSeeData.features.EyeRight <= -0.3f) - proxy.SetPerfectSync("EYEBLINKRIGHT", -openSeeData.features.EyeRight * 1.5f, lastPerfectSync); - else - proxy.SetPerfectSync("EYEBLINKRIGHT", 0, lastPerfectSync); - } - - if (openSeeData.features.EyebrowSteepnessLeft < 0.2f) - proxy.SetPerfectSync("BROWOUTERUPLEFT", -openSeeData.features.EyebrowSteepnessLeft, lastPerfectSync); - else - proxy.SetPerfectSync("BROWOUTERUPLEFT", 0, lastPerfectSync); - - if (openSeeData.features.EyebrowSteepnessRight < 0.2f) - proxy.SetPerfectSync("BROWOUTERUPRIGHT", -openSeeData.features.EyebrowSteepnessRight, lastPerfectSync); - else - proxy.SetPerfectSync("BROWOUTERUPRIGHT", 0, lastPerfectSync); - - if (openSeeData.features.EyeLeft > 0.5f) - proxy.SetPerfectSync("EYEWIDELEFT", openSeeData.features.EyeLeft * 0.7f, lastPerfectSync); - else - proxy.SetPerfectSync("EYEWIDELEFT", 0, lastPerfectSync); - - if (openSeeData.features.EyeRight > 0.5f) - proxy.SetPerfectSync("EYEWIDERIGHT", openSeeData.features.EyeRight * 0.7f, lastPerfectSync); - else - proxy.SetPerfectSync("EYEWIDERIGHT", 0, lastPerfectSync); - - if (trackMouth) { - if (openSeeData.features.MouthWide < 0.5f) - proxy.SetPerfectSync("MOUTHPUCKER", -openSeeData.features.MouthWide * 0.3f, lastPerfectSync); - else - proxy.SetPerfectSync("MOUTHPUCKER", 0, lastPerfectSync); - - if (openSeeData.features.MouthOpen > 0.0f) { - proxy.SetPerfectSync("JAWOPEN", openSeeData.features.MouthOpen, lastPerfectSync); - proxy.SetPerfectSync("MOUTHCLOSE", 0, lastPerfectSync); - } else if (openSeeData.features.MouthOpen < -0.0f) { - proxy.SetPerfectSync("MOUTHCLOSE", openSeeData.features.MouthOpen, lastPerfectSync); - proxy.SetPerfectSync("JAWOPEN", 0, lastPerfectSync); - } else { - proxy.SetPerfectSync("JAWOPEN", 0, lastPerfectSync); - proxy.SetPerfectSync("MOUTHCLOSE", 0, lastPerfectSync); - } - - if (openSeeData.features.MouthCornerInOutLeft > 0.3f) - proxy.SetPerfectSync("MOUTHLEFT", openSeeData.features.MouthCornerInOutLeft * 0.5f, lastPerfectSync); - else - proxy.SetPerfectSync("MOUTHLEFT", 0, lastPerfectSync); - - if (openSeeData.features.MouthCornerInOutRight > 0.3f) - proxy.SetPerfectSync("MOUTHRIGHT", openSeeData.features.MouthCornerInOutRight * 0.5f, lastPerfectSync); - else - proxy.SetPerfectSync("MOUTHRIGHT", 0, lastPerfectSync); - - if (openSeeData.features.MouthCornerUpDownLeft > 0.3f) - proxy.SetPerfectSync("MOUTHSMILELEFT", openSeeData.features.MouthCornerUpDownLeft * 0.5f, lastPerfectSync); - else if (openSeeData.features.MouthCornerUpDownLeft < -0.3f) - proxy.SetPerfectSync("MOUTHFROWNLEFT", -openSeeData.features.MouthCornerUpDownLeft, lastPerfectSync); - else { - proxy.SetPerfectSync("MOUTHSMILELEFT", 0, lastPerfectSync); - proxy.SetPerfectSync("MOUTHFROWNLEFT", 0, lastPerfectSync); - } - - if (openSeeData.features.MouthCornerUpDownRight > 0.3f) - proxy.SetPerfectSync("MOUTHSMILERIGHT", openSeeData.features.MouthCornerUpDownRight * 0.5f, lastPerfectSync); - else if (openSeeData.features.MouthCornerUpDownLeft < -0.3f) - proxy.SetPerfectSync("MOUTHFROWNRIGHT", -openSeeData.features.MouthCornerUpDownRight, lastPerfectSync); - else { - proxy.SetPerfectSync("MOUTHSMILERIGHT", 0, lastPerfectSync); - proxy.SetPerfectSync("MOUTHFROWNRIGHT", 0, lastPerfectSync); - } - } - } - } - - void UpdateBrows() { - if ((browClips == null && (faceMesh == null || faceType < 0)) || openSeeData == null) { + + float t = Mathf.Clamp((float)mouthInterpolationCount / openSeeIKTarget.averageInterpolations, 0f, 0.985f); + mouthInterpolationCount++; + + if (currentExpression != null && !currentExpression.enableVisemes) return; - } - if (browInterpolate == null) - browInterpolate = new TimeInterpolate(); - - float t = browInterpolate.Interpolate(); - float strength = eyebrowStrength; + + float expressionFactor = 1f; if (currentExpression != null) - strength *= currentExpressionEyebrowWeight; - - if (!useCameraPerfectSync || !proxy.HasPerfectSync()) { - if (!skipApply && browClips == null) { - if (browUpIndex > -1 && strength > 0f) - faceMesh.SetBlendShapeWeight(browUpIndex, strength * Mathf.Lerp(lastBrowStates[0], currentBrowStates[0], t)); - if (browDownIndex > -1 && strength > 0f) - faceMesh.SetBlendShapeWeight(browDownIndex, strength * Mathf.Lerp(lastBrowStates[1], currentBrowStates[1], t)); - if (browAngryIndex > -1 && strength > 0f) - faceMesh.SetBlendShapeWeight(browAngryIndex, strength * Mathf.Lerp(lastBrowStates[2], currentBrowStates[2], t)); - if (browSorrowIndex > -1 && strength > 0f) - faceMesh.SetBlendShapeWeight(browSorrowIndex, strength * Mathf.Lerp(lastBrowStates[3], currentBrowStates[3], t)); - } - if (browClips != null && strength > 0f) { - if (lastBrowUpDown > 0f) - proxy.AccumulateValue(browClips[0], strength * Mathf.Lerp(lastBrowStates[0], currentBrowStates[0], t)); - else if (lastBrowUpDown < 0f) - proxy.AccumulateValue(browClips[1], strength * Mathf.Lerp(lastBrowStates[1], currentBrowStates[1], t)); - } - } + expressionFactor = currentExpression.visemeFactor; - if (lastBrows < openSeeData.time) { - lastBrows = openSeeData.time; - float upDownStrength = (openSeeData.features.EyebrowUpDownLeft + openSeeData.features.EyebrowUpDownRight) / 2f; - float stabilizer = 0.3f; - if (eyebrowZero > 0) { - if (upDownStrength > eyebrowZero) - upDownStrength = (upDownStrength - eyebrowZero) / (1f - eyebrowZero); - else - upDownStrength = (upDownStrength - eyebrowZero) / (1f + eyebrowZero); - } else if (eyebrowZero < 0) { - if (upDownStrength < eyebrowZero) - upDownStrength = (upDownStrength - eyebrowZero) / (1f + eyebrowZero); - else - upDownStrength = (upDownStrength - eyebrowZero) / (1f - eyebrowZero); - } - - float magnitude = Mathf.Clamp(Mathf.Abs(upDownStrength - lastBrowUpDown) * eyebrowSensitivity, -1f, 1f); - float factor = 1f; - if (openSeeData.rawEuler.y < turnLeftBoundaryAngle || openSeeData.rawEuler.y > turnRightBoundaryAngle) { - factor = 0.7f; - stabilizer *= 2; - } - if (upDownStrength > 0 && (eyebrowIsMoving > 0 || magnitude > stabilizer)) { - upDownStrength = factor * Mathf.Clamp(upDownStrength / 0.6f, 0f, 1f); - if (magnitude > stabilizer) - eyebrowIsMoving = 5; - } else if (upDownStrength < 0 && (eyebrowIsMoving > 0 || magnitude > stabilizer)) { - upDownStrength = -factor * Mathf.Clamp(upDownStrength / -0.2f, 0f, 1f); - if (magnitude > stabilizer) - eyebrowIsMoving = 5; - } else if (upDownStrength > stabilizer || upDownStrength < stabilizer) { - upDownStrength = lastBrowUpDown; - } else { - upDownStrength = 0f; - } - if (eyebrowIsMoving > 0) - eyebrowIsMoving--; - upDownStrength = Mathf.LerpUnclamped(lastBrowUpDown, upDownStrength, 1f - eyebrowSmoothing); - lastBrowUpDown = upDownStrength; - - for (int i = 0; i < 4; i++) - lastBrowStates[i] = Mathf.Lerp(lastBrowStates[i], currentBrowStates[i], t); - browInterpolate.UpdateTime(openSeeData.time); - - if (browClips != null) { - currentBrowStates[0] = upDownStrength; - currentBrowStates[1] = -upDownStrength; - } else if (faceType == 0) { - if (browUpIndex == -1 || browAngryIndex == -1 || browSorrowIndex == -1) - return; - if (upDownStrength > 0) { - currentBrowStates[0] = upDownStrength * 100f; - currentBrowStates[2] = 0f; - currentBrowStates[3] = 0f; - } else if (upDownStrength < 0) { - currentBrowStates[0] = 0f; - currentBrowStates[2] = -upDownStrength * 25f; - currentBrowStates[3] = -upDownStrength * 25f; - } else { - currentBrowStates[0] = 0f; - currentBrowStates[2] = 0f; - currentBrowStates[3] = 0f; - } - } else if (faceType == 1) { - if (browUpIndex == -1 || browDownIndex == -1 || browAngryIndex == -1 || browSorrowIndex == -1) - return; - if (upDownStrength > 0) { - currentBrowStates[0] = upDownStrength * 100f; - currentBrowStates[1] = 0f; - currentBrowStates[2] = 0f; - currentBrowStates[3] = 0f; - } else if (upDownStrength < 0) { - currentBrowStates[0] = 0f; - currentBrowStates[1] = -upDownStrength * 70f; - currentBrowStates[2] = 0f; - currentBrowStates[3] = 0f; - } else { - currentBrowStates[0] = 0f; - currentBrowStates[1] = 0f; - currentBrowStates[2] = 0f; - currentBrowStates[3] = 0f; - } - } - } - } - - void FindFaceMesh() { - if (lastAvatar == vrmBlendShapeProxy) - return; - if (visemePresetMap == null) - InitCatsData(); - lastAvatar = vrmBlendShapeProxy; - animator = lastAvatar.gameObject.GetComponent(); - - if (animator != null) { - haveJawParameter = false; - for (int i = 0; i < animator.parameterCount; i++) { - if (animator.parameters[i].name == "JawMovement") { - haveJawParameter = true; - break; - } - } - jawBone = animator.GetBoneTransform(HumanBodyBones.Jaw); - for (int i = 0; i < humanBodyBones.Length; i++) { - if (humanBodyBones[i] >= 0 && humanBodyBones[i] < HumanBodyBones.LastBone) - humanBodyBoneTransforms[i] = animator.GetBoneTransform(humanBodyBones[i]); - else - humanBodyBoneTransforms[i] = null; - } - } - - proxy.UpdateAvatar(lastAvatar, animator); - - faceMesh = null; - faceType = -1; - browUpIndex = -1; - browDownIndex = -1; - browAngryIndex = -1; - browSorrowIndex = -1; - browClips = null; - lastBrowStates = new float[] {0f, 0f, 0f, 0f}; - currentBrowStates = new float[] {0f, 0f, 0f, 0f}; - - if (vrmBlendShapeProxy == null) - return; - - HashSet visemeClipNames = new HashSet(); - foreach (var key in fullVisemePresets) - if (key.Preset == BlendShapePreset.Unknown && key.Name != "") - visemeClipNames.Add(key.Name.ToUpper()); - - // Check if the model has set up blendshape clips. Thanks do Deat for this idea! - string foundClipUp = null; - string foundClipDown = null; - HashSet foundVisemeClips = new HashSet(); - foreach (BlendShapeClip clip in vrmBlendShapeProxy.BlendShapeAvatar.Clips) { - if (clip.Preset == BlendShapePreset.Unknown && clip.BlendShapeName != null) { - string name = clip.BlendShapeName.ToUpper(); - if (name == "BROWS UP") - foundClipUp = clip.BlendShapeName; - if (name == "BROWS DOWN") - foundClipDown = clip.BlendShapeName; - if (visemeClipNames.Contains(name)) - foundVisemeClips.Add(name); - } - } - haveFullVisemeSet = false; - if (visemeClipNames.SetEquals(foundVisemeClips)) { - Debug.Log("Detected full viseme set on avatar."); - haveFullVisemeSet = true; - } - if (foundClipUp != null && foundClipDown != null) { - browClips = new BlendShapeKey[2] { - BlendShapeKey.CreateUnknown(foundClipUp), - BlendShapeKey.CreateUnknown(foundClipDown) - }; - return; - } - - // Otherwise try to find direct blendshapes for VRoid and Cecil Henshin models. - Component[] meshes = vrmBlendShapeProxy.gameObject.GetComponentsInChildren(); - foreach (SkinnedMeshRenderer renderer in meshes) { - Mesh mesh = renderer.sharedMesh; - - for (int i = 0; i < mesh.blendShapeCount; i++) { - string bsName = mesh.GetBlendShapeName(i); - if (bsName.Contains("BRW") && bsName.Contains("Surprised")) { - browUpIndex = i; - faceType = 0; - } else if (bsName.Contains("BRW") && bsName.Contains("Angry")) { - browAngryIndex = i; - faceType = 0; - } else if (bsName.Contains("BRW") && bsName.Contains("Sorrow")) { - browSorrowIndex = i; - faceType = 0; - } else if (bsName == "Oko") { - browAngryIndex = i; - faceType = 1; - } else if (bsName == "Yowa") { - browSorrowIndex = i; - faceType = 1; - } else if (bsName == "Down") { - browDownIndex = i; - faceType = 1; - } else if (bsName == "Up") { - browUpIndex = i; - faceType = 1; - } - } - if (faceType > -1) { - faceMesh = renderer; - return; - } + for (int i = 0; i < 5; i++) { + float interpolated = Mathf.Lerp(lastMouthStates[i], currentMouthStates[i], t); + vrmBlendShapeProxy.ImmediatelySetValue(visemePresetMap[i], interpolated * expressionFactor * visemeFactor); } } @@ -1164,154 +319,55 @@ public class OpenSeeVRMDriver : MonoBehaviour { public BlendShapePreset blendShapePreset; [Tooltip("When this name is set, it will be used to create a custom blendshape key.")] public string customBlendShapeName = ""; - [Tooltip("When disabled, this expression is considered a base expression. Only one base expression can be active at a time. Otherwise it can be added on top of other expressions.")] - public bool additive = false; [Tooltip("The weight determines the value the expression blend shape should be set to.")] [Range(0, 1)] public float weight = 1f; [Tooltip("Some expressions involving the mouth require visemes to be weakened, which can be set using this factor. Setting it to 0 is the same as turning enableVisemes off.")] [Range(0, 1)] public float visemeFactor = 1f; - [Tooltip("Some expressions involving the eyebrows require the eyebrow weight to be changed. Setting this weight to 0 will disable eyebrow tracking for this expression. Setting it to 1 enables it fully.")] - [Range(0, 1)] - public float eyebrowWeight = 1f; - [Tooltip("This is the transition time for changing expressions. Setting it to 0 makes the transition instant.")] - [Range(0, 1000)] - public float transitionTime = 0f; [Tooltip("If the expression is not compatible with visemes, it can be turned off here.")] public bool enableVisemes = true; [Tooltip("If the expression is not compatible with blinking, it can be turned off here.")] public bool enableBlinking = true; [Tooltip("This can be set to a virtual key value. If this key is pressed together with shift and control, the expression will trigger as an override.")] public int hotkey = -1; - [Tooltip("If this is set, the shift key has to be pressed for the hotkey to trigger.")] - public bool shiftKey = false; - [Tooltip("If this is set, the ctrl key has to be pressed for the hotkey to trigger.")] - public bool ctrlKey = false; - [Tooltip("If this is set, the alt key has to be pressed for the hotkey to trigger.")] - public bool altKey = false; - [Tooltip("If this is set, the expression will toggle, otherwise it will only be active while this is pressed.")] - public bool toggle = true; [Tooltip("This is the weight for this class's error when training the model.")] public float errorWeight = 1f; [HideInInspector] public BlendShapeKey blendShapeKey; - [HideInInspector] - public bool toggled = false; - [HideInInspector] - public bool triggered = false; - [HideInInspector] - public bool reached = true; - [HideInInspector] - public bool lastActive = false; - - private float stateChangedTime = -1f; - private float stateChangedWeight = 0f; - private float lastWeight = 0f; - private float targetWeight = 0f; - private float remainingWeight = 0f; - private float currentTransitionTime = 0f; - - public float GetWeight(float baseTransitionTime) { - if (triggered != lastActive) - reached = false; - if (reached) { - if (triggered) { - lastWeight = 1f; - return 1f; - } else { - lastWeight = 0f; - return 0f; - } - } - if (triggered != lastActive) { - stateChangedTime = Time.time; - stateChangedWeight = lastWeight; - currentTransitionTime = transitionTime; - lastActive = triggered; - if (triggered) { - targetWeight = 1f; - remainingWeight = 1f - lastWeight; - } else { - targetWeight = 0f; - remainingWeight = lastWeight; - } - } - if (baseTransitionTime < currentTransitionTime) - currentTransitionTime = baseTransitionTime; - lastWeight = Mathf.Lerp(stateChangedWeight, targetWeight, Mathf.Min((Time.time - stateChangedTime) / (currentTransitionTime * 0.001f * remainingWeight), 1f)); - if (lastWeight >= 0.9999f && triggered) { - lastWeight = 1f; - reached = true; - } - if (lastWeight <= 0.0001f && !triggered) { - lastWeight = 0f; - reached = true; - } - return lastWeight; - } - public OpenSeeVRMExpression(string trigger, BlendShapePreset preset, bool additive, float weight, float factor, float eyebrows, bool visemes, bool blinking, int hotkey, bool shiftKey, bool ctrlKey, bool altKey, bool toggle, float errorWeight, float transitionTime) { + public OpenSeeVRMExpression(string trigger, BlendShapePreset preset, float weight, float factor, bool visemes, bool blinking, int hotkey, float errorWeight) { this.trigger = trigger; this.blendShapePreset = preset; - this.additive = additive; this.weight = weight; this.visemeFactor = factor; - this.eyebrowWeight = eyebrows; this.enableVisemes = visemes; this.enableBlinking = blinking; this.hotkey = hotkey; - this.shiftKey = shiftKey; - this.ctrlKey = ctrlKey; - this.altKey = altKey; - this.toggle = toggle; this.errorWeight = errorWeight; - this.transitionTime = transitionTime; } - public OpenSeeVRMExpression(string trigger, string name, bool additive, float weight, float factor, float eyebrows, bool visemes, bool blinking, int hotkey, bool shiftKey, bool ctrlKey, bool altKey, bool toggle, float errorWeight, float transitionTime) { + public OpenSeeVRMExpression(string trigger, string name, float weight, float factor, bool visemes, bool blinking, int hotkey, float errorWeight) { this.trigger = trigger; this.customBlendShapeName = name; - this.additive = additive; this.weight = weight; this.visemeFactor = factor; - this.eyebrowWeight = eyebrows; this.enableVisemes = visemes; this.enableBlinking = blinking; this.hotkey = hotkey; - this.shiftKey = shiftKey; - this.ctrlKey = ctrlKey; - this.altKey = altKey; - this.toggle = toggle; this.errorWeight = errorWeight; - this.transitionTime = transitionTime; } } - - public OpenSeeVRMExpression GetExpression(string trigger) { - if (!expressionMap.ContainsKey(trigger)) - return null; - return expressionMap[trigger]; - } public void InitExpressionMap() { - toggledExpression = null; - lastExpression = null; - currentExpression = null; - overridden = false; - continuedPress = new HashSet(); expressionMap = new Dictionary(); openSeeExpression.weightMap = new Dictionary(); foreach (var expression in expressions) { - expression.toggled = false; - expression.triggered = false; - expression.lastActive = false; - expression.reached = true; openSeeExpression.weightMap.Add(expression.trigger, expression.errorWeight); if (expression.customBlendShapeName != "") - expression.blendShapeKey = BlendShapeKey.CreateUnknown(expression.customBlendShapeName); + expression.blendShapeKey = new BlendShapeKey(expression.customBlendShapeName); else - expression.blendShapeKey = BlendShapeKey.CreateFromPreset(expression.blendShapePreset); + expression.blendShapeKey = new BlendShapeKey(expression.blendShapePreset); expressionMap.Add(expression.trigger, expression); } } @@ -1325,139 +381,48 @@ public class OpenSeeVRMDriver : MonoBehaviour { currentExpression = null; return; } + foreach (var expression in expressionMap.Values) { + vrmBlendShapeProxy.ImmediatelySetValue(expression.blendShapeKey, 0f); + } if (openSeeExpression == null) { currentExpression = null; return; } - bool trigger = false; - currentExpression = null; - if (hotkeys) { - bool shiftKey = (GetAsyncKeyState(0x10) & 0x8000U) != 0; - bool ctrlKey = (GetAsyncKeyState(0x11) & 0x8000U) != 0; - bool altKey = (GetAsyncKeyState(0x12) & 0x8000U) != 0; + bool anyPressed = false; + bool modifiers = (GetAsyncKeyState(0x10) & 0x8000U) != 0; + modifiers = ((GetAsyncKeyState(0x11) & 0x8000U) != 0) || modifiers; + if (modifiers) { foreach (var expression in expressionMap.Values) { - // Clean up inconsistent states - if (!expression.toggle && expression.toggled) { - expression.toggled = false; - if (toggledExpression == expression) { - toggledExpression = null; + if (expression.hotkey >= 0 && expression.hotkey < 256 && (GetAsyncKeyState(expression.hotkey) & 0x8000) != 0) { + anyPressed = true; + if (continuedPress != expression.hotkey && overridden && currentExpression == expression) { overridden = false; + currentExpression = null; + continuedPress = expression.hotkey; + break; } - if (continuedPress.Contains(expression)) - continuedPress.Remove(expression); - } - if (expression.toggled && expression.additive && toggledExpression == expression) { - toggledExpression = null; - overridden = false; - } - if (expression.toggled && !expression.additive && toggledExpression != expression) { - if (toggledExpression == null && !overridden) { - toggledExpression = expression; + if (continuedPress != expression.hotkey) { overridden = true; - } else - expression.toggled = false; - } - - // Automatically trigger toggled expressions - if ((expression.additive || expression == toggledExpression) && expression.toggled) - expression.triggered = true; - else - expression.triggered = false; - - if (expression.hotkey >= 0 && expression.hotkey < 256 && (GetAsyncKeyState(expression.hotkey) & 0x8000) != 0 && shiftKey == expression.shiftKey && ctrlKey == expression.ctrlKey && altKey == expression.altKey) { - if (!expression.toggle && continuedPress.Contains(expression)) - continuedPress.Remove(expression); - if (!continuedPress.Contains(expression)) { - // Generally, turn on expressions when their hotkey is pressed - expression.triggered = true; - if (expression.toggle) { - // If can be toggled, toggle it and update the triggered value accordingly - expression.toggled = !expression.toggled; - expression.triggered = expression.toggled; - // If it is a base expression - if (!expression.additive) { - if (expression.toggled) { - // Override expression detection - overridden = true; - // Mark it as the current base expression while unmarking any other - toggledExpression = expression; - foreach (var otherExpression in expressionMap.Values) { - if (otherExpression.toggle && !otherExpression.additive && otherExpression != expression) { - otherExpression.toggled = false; - otherExpression.triggered = false; - } - } - } else { - // Unmark it as the current base expression if it was untoggled - if (toggledExpression == expression) { - toggledExpression = null; - overridden = false; - } - } - } - continuedPress.Add(expression); - } else { - if (!expression.additive) { - // If it's a base expression being triggered on, override expression detection - trigger = true; - currentExpression = expression; - } - } + currentExpression = expression; + continuedPress = expression.hotkey; + break; } - } else { - continuedPress.Remove(expression); } } } - - if (overridden && !trigger) - currentExpression = toggledExpression; - if (trigger && overridden && currentExpression != toggledExpression) - toggledExpression.triggered = false; + if (!anyPressed) + continuedPress = -1; - if (!overridden && !trigger) { - if (only30Points || !openSeeExpression.enabled || openSeeExpression.expressionTime + 15f < Time.time || openSeeExpression.expression == null || openSeeExpression.expression == "" || !expressionMap.ContainsKey(openSeeExpression.expression)) { + if (!overridden) { + if (openSeeExpression.expression == null || openSeeExpression.expression == "" || !expressionMap.ContainsKey(openSeeExpression.expression)) { currentExpression = null; - } else { - currentExpression = expressionMap[openSeeExpression.expression]; - currentExpression.triggered = true; + return; } - } else if (!only30Points && openSeeExpression.enabled && openSeeExpression.expressionTime + 15f > Time.time && openSeeExpression.expression != null && openSeeExpression.expression != "" && expressionMap.ContainsKey(openSeeExpression.expression)) { - if (expressionMap[openSeeExpression.expression].additive) - expressionMap[openSeeExpression.expression].triggered = true; + currentExpression = expressionMap[openSeeExpression.expression]; } - if (currentExpression == null && expressionMap.ContainsKey("neutral")) { - currentExpression = expressionMap["neutral"]; - currentExpression.triggered = true; - } - - // Reset limits on expressions - currentExpressionEnableBlinking = true; - currentExpressionEnableVisemes = true; - currentExpressionEyebrowWeight = 1f; - currentExpressionVisemeFactor = 1f; - - float baseTransitionTime = 1000f; - if (currentExpression != null && (!currentExpression.reached || currentExpression.lastActive != currentExpression.triggered) && currentExpression.transitionTime < baseTransitionTime) - baseTransitionTime = currentExpression.transitionTime; - if (lastExpression != currentExpression && lastExpression != null && (!lastExpression.reached || lastExpression.lastActive != lastExpression.triggered) && lastExpression.transitionTime < baseTransitionTime) - baseTransitionTime = lastExpression.transitionTime; - foreach (var expression in expressionMap.Values) { - float weight = expression.GetWeight(baseTransitionTime); - if (weight > 0f) { - proxy.AccumulateValue(expression.blendShapeKey, weight, 1f); - - // Accumulate limits on expressions - currentExpressionEnableBlinking = currentExpressionEnableBlinking && expression.enableBlinking; - currentExpressionEnableVisemes = currentExpressionEnableVisemes && expression.enableVisemes; - currentExpressionEyebrowWeight = Mathf.Min(currentExpressionEyebrowWeight, expression.eyebrowWeight); - currentExpressionVisemeFactor = Mathf.Min(currentExpressionVisemeFactor, expression.visemeFactor); - } - } - proxy.DisableFaceParts(currentExpressionEyebrowWeight < 0.0005f, !currentExpressionEnableBlinking, !currentExpressionEnableVisemes || (currentExpressionVisemeFactor < 0.0005f)); - lastExpression = currentExpression; + vrmBlendShapeProxy.ImmediatelySetValue(currentExpression.blendShapeKey, currentExpression.weight); } void GetLookParameters(ref float lookLeftRight, ref float lookUpDown, bool update, int gazePoint, int right, int left, int topRight, int topLeft, int bottomRight, int bottomLeft) { @@ -1471,8 +436,8 @@ public class OpenSeeVRMDriver : MonoBehaviour { float verticalRadius = (Mathf.Abs(verticalCenter - borderTop) + Mathf.Abs(borderBottom - verticalCenter)) / 2.0f; float x = openSeeData.points3D[gazePoint].x; float y = openSeeData.points3D[gazePoint].y; - float newLookLeftRight = Mathf.Clamp((x - horizontalCenter) / horizontalRadius + gazeCenter.x, -1f, 1f); - float newLookUpDown = Mathf.Clamp((y - verticalCenter) / verticalRadius + gazeCenter.y, -1f, 1f); + float newLookLeftRight = Mathf.Clamp((x - horizontalCenter) / horizontalRadius, -1f, 1f); + float newLookUpDown = Mathf.Clamp((y - verticalCenter) / verticalRadius, -1f, 1f); if (!update) { lookLeftRight = newLookLeftRight; lookUpDown = newLookUpDown; @@ -1485,49 +450,11 @@ public class OpenSeeVRMDriver : MonoBehaviour { } void UpdateGaze() { - if (openSeeData == null || vrmBlendShapeProxy == null || openSeeIKTarget == null || skipApplyEyes) + if (openSeeData == null || vrmBlendShapeProxy == null || openSeeIKTarget == null || !(openSeeIKTarget.averageInterpolations > 0f)) return; float lookUpDown = currentLookUpDown; float lookLeftRight = currentLookLeftRight; - - if (gazeInterpolate == null) - gazeInterpolate = new TimeInterpolate(); - float t = gazeInterpolate.Interpolate(); - - lookLeftRight = Mathf.Lerp(lastLookLeftRight, currentLookLeftRight, t); - lookUpDown = Mathf.Lerp(lastLookUpDown, currentLookUpDown, t); - - if (!openSeeIKTarget.mirrorMotion) - lookLeftRight = -lookLeftRight; - - if (leftEye == null && rightEye == null) { - if (gazeTracking) { - if (lookUpDown > 0f) { - proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.LookUp), gazeFactor.x * lookUpDown); - } else { - proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.LookDown), -gazeFactor.x * lookUpDown); - } - - if (lookLeftRight > 0f) { - proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.LookLeft), gazeFactor.y * lookLeftRight); - } else { - proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.LookRight), -gazeFactor.y * lookLeftRight); - } - } - } else { - if (rightEye != null) - rightEye.localRotation = Quaternion.identity; - if (leftEye != null) - leftEye.localRotation = Quaternion.identity; - if (gazeTracking) { - Quaternion rotation = Quaternion.Slerp(Quaternion.identity, Quaternion.AngleAxis(-gazeFactor.x * gazeStrength * lookUpDown, Vector3.right) * Quaternion.AngleAxis(-gazeFactor.y * gazeStrength * lookLeftRight, Vector3.up), blendShapeWeight); - if (rightEye != null) - rightEye.localRotation = rotation; - if (leftEye != null) - leftEye.localRotation = rotation; - } - } if (lastGaze < openSeeData.time) { GetLookParameters(ref lookLeftRight, ref lookUpDown, false, 66, 36, 39, 37, 38, 41, 40); @@ -1537,12 +464,55 @@ public class OpenSeeVRMDriver : MonoBehaviour { lookUpDown = Mathf.Lerp(currentLookUpDown, lookUpDown, 1f - gazeSmoothing); if (Mathf.Abs(lookLeftRight - currentLookLeftRight) + Mathf.Abs(lookUpDown - currentLookUpDown) > gazeStabilizer) { - lastLookLeftRight = Mathf.Lerp(lastLookLeftRight, currentLookLeftRight, t); - lastLookUpDown = Mathf.Lerp(lastLookUpDown, currentLookUpDown, t); + lastLookLeftRight = currentLookLeftRight; + lastLookUpDown = currentLookUpDown; currentLookLeftRight = lookLeftRight; currentLookUpDown = lookUpDown; lastGaze = openSeeData.time; - gazeInterpolate.UpdateTime(lastGaze); + if (interpolationState < 2) + interpolationState++; + interpolationCount = 0; + } + } + + if (interpolationState < 2) + return; + + float t = Mathf.Clamp((float)interpolationCount / openSeeIKTarget.averageInterpolations, 0f, 0.985f); + lookLeftRight = Mathf.Lerp(lastLookLeftRight, currentLookLeftRight, t); + lookUpDown = Mathf.Lerp(lastLookUpDown, currentLookUpDown, t); + interpolationCount++; + + if (!openSeeIKTarget.mirrorMotion) + lookLeftRight = -lookLeftRight; + + if (leftEye == null || rightEye == null) { + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.LookUp), 0f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.LookDown), 0f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.LookLeft), 0); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.LookRight), 0f); + if (gazeTracking) { + if (lookUpDown > 0f) { + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.LookUp), gazeFactor.x * lookUpDown); + } else { + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.LookDown), -gazeFactor.x * lookUpDown); + } + + if (lookLeftRight > 0f) { + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.LookLeft), gazeFactor.y * lookLeftRight); + } else { + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.LookRight), -gazeFactor.y * lookLeftRight); + } + } + } else { + //vrmLookAtHead.UpdateType = VRM.UpdateType.None; + //vrmLookAtHead.RaiseYawPitchChanged(gazeFactor.y * lookLeftRight, gazeFactor.x * lookUpDown); + rightEye.localRotation = Quaternion.identity; + leftEye.localRotation = Quaternion.identity; + if (gazeTracking) { + Quaternion rotation = Quaternion.AngleAxis(-gazeFactor.x * gazeStrength * lookUpDown, Vector3.right) * Quaternion.AngleAxis(-gazeFactor.y * gazeStrength * lookLeftRight, Vector3.up); + rightEye.localRotation = rotation; + leftEye.localRotation = rotation; } } } @@ -1550,36 +520,69 @@ public class OpenSeeVRMDriver : MonoBehaviour { void BlinkEyes() { if (vrmBlendShapeProxy == null || eyeBlinker == null) return; - if (autoBlink || only30Points) { - if (currentExpressionEnableBlinking) { - float blink = eyeBlinker.Blink(); - if (!useCameraPerfectSync || ! proxy.HasPerfectSync()) - proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Blink), blink, 1); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_R), 0f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_L), 0f); + if (autoBlink) { + if (eyeBlinker.Blink() && (currentExpression == null || currentExpression.enableBlinking)) { + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_R), 1f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_L), 1f); } - } else if (openSeeExpression != null && openSeeExpression.openSee != null && openSeeData != null) { - if (!currentExpressionEnableBlinking) + } else if (openSeeExpression != null && openSeeExpression.openSee != null) { + if (currentExpression != null && !currentExpression.enableBlinking) return; float right = 1f; float left = 1f; - float upDownAngle = openSeeData.rawEuler.x; - while (upDownAngle < 0f) - upDownAngle += 360f; - while (upDownAngle >= 360f) - upDownAngle -= 360f; - if (lookDownCompensation && upDownAngle > turnDownBoundaryAngle - lookDownAdjustment - wasLookingDown && autoBlinkLookingDown) { - if (!(wasLookingDown > 0f)) - eyeBlinker.Blink(); - float blink = eyeBlinker.Blink(); - if (!useCameraPerfectSync || ! proxy.HasPerfectSync()) - proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Blink), blink); - return; - } + if (openSeeData != null && lastBlink < openSeeData.time) { + lastBlink = openSeeData.time; + float openThreshold = eyeOpenedThreshold; + + if (openSeeData.rawEuler.y < turnLeftBoundaryAngle || openSeeData.rawEuler.y > turnRightBoundaryAngle) + openThreshold = Mathf.Lerp(openThreshold, eyeClosedThreshold, 0.4f); + + if (openSeeData.rightEyeOpen > openThreshold) + right = 0f; + else if (openSeeData.rightEyeOpen < eyeClosedThreshold) + right = 1f; + else + right = 1f - (openSeeData.rightEyeOpen - eyeClosedThreshold) / (openThreshold - eyeClosedThreshold); - if (blinkInterpolate == null) - blinkInterpolate = new TimeInterpolate(); - float t = blinkInterpolate.Interpolate(); + if (openSeeData.leftEyeOpen > openThreshold) + left = 0f; + else if (openSeeData.leftEyeOpen < eyeClosedThreshold) + left = 1f; + else + left = 1f - (openSeeData.leftEyeOpen - eyeClosedThreshold) / (openThreshold - eyeClosedThreshold); + + if (openSeeData.rawEuler.y < turnLeftBoundaryAngle) + left = right; + if (openSeeData.rawEuler.y > turnRightBoundaryAngle) + right = left; + + lastBlinkLeft = currentBlinkLeft; + lastBlinkRight = currentBlinkRight; + currentBlinkLeft = Mathf.Lerp(currentBlinkLeft, left, 1f - blinkSmoothing); + currentBlinkRight = Mathf.Lerp(currentBlinkRight, right, 1f - blinkSmoothing); + + if (left == 0f) + currentBlinkLeft = 0f; + if (right == 0f) + currentBlinkRight = 0f; + if (left == 1f) + currentBlinkLeft = 1f; + if (right == 1f) + currentBlinkRight = 1f; + + if (blinkInterpolationState < 2) + blinkInterpolationState++; + } + + if (blinkInterpolationState < 2) + return; + + float t = Mathf.Clamp((float)blinkInterpolationCount / openSeeIKTarget.averageInterpolations, 0f, 0.985f); + blinkInterpolationCount++; left = Mathf.Lerp(lastBlinkLeft, currentBlinkLeft, t); right = Mathf.Lerp(lastBlinkRight, currentBlinkRight, t); @@ -1590,80 +593,8 @@ public class OpenSeeVRMDriver : MonoBehaviour { right = tmp; } - if (!useCameraPerfectSync || !proxy.HasPerfectSync()) { - if (linkBlinks && !allowWinking) { - float v = Mathf.Max(left, right); - proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Blink), v); - } else { - proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Blink_R), right); - proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Blink_L), left); - } - } - - if (openSeeData != null && lastBlink < openSeeData.time) { - lastBlink = openSeeData.time; - blinkInterpolate.UpdateTime(lastBlink); - float openThreshold = eyeOpenedThreshold; - float closedThreshold = eyeClosedThreshold; - - if (openSeeData.rawEuler.y < turnLeftBoundaryAngle || openSeeData.rawEuler.y > turnRightBoundaryAngle) - openThreshold = Mathf.Lerp(eyeOpenedThreshold, eyeClosedThreshold, 0.4f); - - if (lookDownCompensation && upDownAngle > turnDownBoundaryAngle - lookDownAdjustment - wasLookingDown) { - openThreshold = Mathf.Lerp(eyeOpenedThreshold, eyeClosedThreshold, 0.85f); - closedThreshold = Mathf.Lerp(eyeClosedThreshold, 0f, 0.6f); - if (upDownAngle > turnDownBoundaryAngle - lookDownAdjustment + 10f) { - openThreshold = 0.1f; - closedThreshold = 0f; - } - wasLookingDown = 1.5f; - } else { - wasLookingDown = 0f; - } - - if (openSeeData.rightEyeOpen > openThreshold) - right = 0f; - else if (openSeeData.rightEyeOpen < closedThreshold) - right = 1f; - else - right = 1f - (openSeeData.rightEyeOpen - closedThreshold) / (openThreshold - closedThreshold); - - if (openSeeData.leftEyeOpen > openThreshold) - left = 0f; - else if (openSeeData.leftEyeOpen < closedThreshold) - left = 1f; - else - left = 1f - (openSeeData.leftEyeOpen - closedThreshold) / (openThreshold - closedThreshold); - - if (openSeeData.rawEuler.y < turnLeftBoundaryAngle) - left = right; - if (openSeeData.rawEuler.y > turnRightBoundaryAngle) - right = left; - - if (linkBlinks) { - if (Mathf.Abs(right - left) < smartWinkThreshold || !allowWinking) { - float v = Mathf.Max(left, right); - if (v < 0.3f) - v = Mathf.Min(left, right); - left = v; - right = v; - } - } - - lastBlinkLeft = Mathf.Lerp(lastBlinkLeft, currentBlinkLeft, t); - lastBlinkRight = Mathf.Lerp(lastBlinkRight, currentBlinkRight, t); - currentBlinkLeft = Mathf.Lerp(currentBlinkLeft, left, 1f - blinkSmoothing); - currentBlinkRight = Mathf.Lerp(currentBlinkRight, right, 1f - blinkSmoothing); - - if (left < 0.00001f) - currentBlinkLeft = 0f; - if (right < 0.00001f) - currentBlinkRight = 0f; - if (left > 0.99999f) - currentBlinkLeft = 1f; - if (right > 0.99999f) - currentBlinkRight = 1f; - } + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_R), right); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_L), left); } } @@ -1679,51 +610,33 @@ public class OpenSeeVRMDriver : MonoBehaviour { public float rangeDurLower = 0.1f; [Tooltip("This is the maximum duration of eye blinks.")] public float rangeDurUpper = 0.2f; - [Tooltip("When set, blinks will be smooth instead of instantaneous.")] - public bool smoothBlink = true; private float blinkEyeRate; private float blinkEndTime = 1.0f; private float previousBlinkEyeRate; private float blinkEyeTime; private bool triggered = false; - private float blinkStart = 0f; - private float blinkDur = 0f; - - private float SmoothBlink() { - if (!smoothBlink) - return 1f; - float fourth = blinkDur / 3f; - float closeMax = blinkStart + fourth; - float openMin = blinkStart + 2f * fourth; - if (Time.time < closeMax) - return (Time.time - blinkStart) / fourth; - if (Time.time > openMin) - return 1f - Mathf.Min((Time.time - openMin) / fourth, 1f); - return 1f; - } + private bool result = false; - public float Blink() + public bool Blink() { - float result = 0f; if (triggered && Time.time > blinkEndTime) { + result = false; triggered = false; blinkEndTime = 0.0f; if (UnityEngine.Random.Range(0f, 1f) < doubleProb) { blinkEyeTime = Time.time + UnityEngine.Random.Range(0.075f, 0.125f); } } else if (triggered) { - result = SmoothBlink(); + result = true; } if (!triggered && Time.time > blinkEyeTime) { previousBlinkEyeRate = blinkEyeRate; blinkEyeTime = Time.time + blinkEyeRate; - triggered = true; - blinkStart = Time.time; - blinkDur = UnityEngine.Random.Range(rangeDurLower, rangeDurUpper); if (blinkEndTime < 1.0f) { - result = SmoothBlink(); + result = true; } - blinkEndTime = blinkStart + blinkDur; + triggered = true; + blinkEndTime = Time.time + UnityEngine.Random.Range(rangeDurLower, rangeDurUpper); while (previousBlinkEyeRate == blinkEyeRate) { blinkEyeRate = UnityEngine.Random.Range(rangeLower, rangeUpper); } @@ -1733,9 +646,7 @@ public class OpenSeeVRMDriver : MonoBehaviour { } public void InitializeLipSync() { - #if WINDOWS_BUILD active = false; - lastAudioTime = -1f; if (catsData == null) InitCatsData(); if (!isCanned && clip != null) @@ -1772,7 +683,8 @@ public class OpenSeeVRMDriver : MonoBehaviour { freq = maxFreq; lastMic = mic; - try { Microphone.GetDeviceCaps(lastMic, out minFreq, out maxFreq); } catch (Exception e) { Debug.LogError("Failed to get device capabilities: " + e); } + if (mic != null) + Microphone.GetDeviceCaps(lastMic, out minFreq, out maxFreq); if (maxFreq > 0) freq = maxFreq; @@ -1787,12 +699,11 @@ public class OpenSeeVRMDriver : MonoBehaviour { inited = true; } - try { clip = Microphone.Start(lastMic, true, 1, freq); } catch (Exception e) { Debug.LogError("Failed to start microphone: " + e); lipSync = false;} + clip = Microphone.Start(lastMic, true, 1, freq); channels = clip.channels; partialAudio = new float[1024 * channels]; lastPos = 0; active = true; - #endif } float[] ReadMic() { @@ -1824,41 +735,13 @@ public class OpenSeeVRMDriver : MonoBehaviour { } void ProcessBuffer(float[] buffer) { - #if WINDOWS_BUILD if (buffer == null) return; audioVolume = 0f; - float leftVolume = 0f; - float rightVolume = 0f; - bool channel = false; - foreach (float v in buffer) { - float sample = Mathf.Abs(v); - audioVolume += sample; - if (channels > 1) { - if (channel) - rightVolume += sample; - channel = !channel; - } - } - if (channels > 1) { - leftVolume = audioVolume - rightVolume; - if (rightVolume < leftVolume / 3f) { - audioVolume = 2f * leftVolume; - for (int i = 0; i + 1 < buffer.Length; i += 2) { - buffer[i + 1] = buffer[i]; - } - } else if (leftVolume < rightVolume / 3f) { - audioVolume = 2f * rightVolume; - for (int i = 0; i + 1 < buffer.Length; i += 2) { - buffer[i] = buffer[i + 1]; - } - } - } + foreach (float v in buffer) + audioVolume += Mathf.Abs(v); audioVolume /= buffer.Length; - - if (audioVolume > 0f) - lastAudioTime = fakeTimeTime; int totalLen = partialPos + buffer.Length; int bufferPos = 0; @@ -1894,11 +777,9 @@ public class OpenSeeVRMDriver : MonoBehaviour { Array.Copy(buffer, bufferPos, partialAudio, partialPos, buffer.Length - bufferPos); partialPos += (buffer.Length - bufferPos) / channels; } - #endif } void OnAudioFilterRead(float[] data, int channels) { - #if WINDOWS_BUILD if (isCanned) { if (channels > 3) { Debug.Log("Audio with more than 3 channels is not supported."); @@ -1916,15 +797,9 @@ public class OpenSeeVRMDriver : MonoBehaviour { if (isCanned) ProcessBuffer(buffer); } - #endif } void ReadAudio() { - #if WINDOWS_BUILD - if (lastAudioTime >= 0f && Time.time > lastAudioTime + 3f && lipSync) { - Debug.Log("Audio device might have disappeared, reinitializing lip sync."); - InitializeLipSync(); - } if (clip == null) return; if (OVRLipSync.IsInitialized() != OVRLipSync.Result.Success) { @@ -1936,11 +811,9 @@ public class OpenSeeVRMDriver : MonoBehaviour { return; if (!isCanned) ProcessBuffer(buffer); - #endif } void CreateContext() { - #if WINDOWS_BUILD lock (this) { if (context == 0) { if (OVRLipSync.CreateContext(ref context, provider) != OVRLipSync.Result.Success) { @@ -1949,83 +822,33 @@ public class OpenSeeVRMDriver : MonoBehaviour { } } } - #endif } void Start() { InitExpressionMap(); - proxy = new OpenSeeBlendShapeProxy(this); - humanBodyBones = (HumanBodyBones[])Enum.GetValues(typeof(HumanBodyBones)); - humanBodyBoneTransforms = new Transform[humanBodyBones.Length]; - humanBodyBoneRotations = new Quaternion[humanBodyBones.Length]; - } - - public void SetProxyValues(Dictionary dict) { - foreach (var kv in dict) { - proxy.AccumulateValue(kv.Key, kv.Value, 1f); - } - } - - public void SetExternalPerfectSync(Dictionary blendshapes, float time) { - if (blendshapes == null) { - proxy.ClearPerfectSync(); - return; - } - foreach (var entry in blendshapes) - proxy.SetPerfectSync(entry.Key, entry.Value, time, 1f); } void RunUpdates() { if (openSeeExpression != null && openSeeExpression.openSee != null) { openSeeData = openSeeExpression.openSee.GetOpenSeeData(openSeeExpression.faceId); - if (openSeeData != null && openSeeData.fit3DError > openSeeExpression.openSee.maxFit3DError) + if (openSeeData.fit3DError > openSeeExpression.openSee.maxFit3DError) openSeeData = null; } if (initializeLipSync) { InitializeLipSync(); initializeLipSync = false; } - proxy.SetWeight(blendShapeWeight); - proxy.Clear(); - FindFaceMesh(); - if (!skipApply) - UpdateExpression(); - if (!skipApply) - BlinkEyes(); - bool doMouthTracking = true; - #if WINDOWS_BUILD + UpdateExpression(); + UpdateGaze(); + BlinkEyes(); ReadAudio(); if (lipSync) { - if (!skipApply) - doMouthTracking = ApplyVisemes(); - } - #endif - if (doMouthTracking && !skipApply) + ApplyVisemes(); + } else { ApplyMouthShape(); - if (!skipApply) - UpdatePerfectSync(); - if (!skipApply && vrmBlendShapeProxy != null && browClips == null) - proxy.Apply(); - if (!skipApply) - UpdateBrows(); - if (!skipApply && vrmBlendShapeProxy != null && browClips != null) - proxy.Apply(); + } } - - void LateUpdate() { - if (!skipApplyJaw && jawBone != null && jawBoneAnimation != null && !haveJawParameter) { - jawBone.localRotation = jawRotation; - } - if (!skipApplyEyes && gazeTracking && !only30Points) { - UpdateGaze(); - } - // If blendshapes are received over VMC, apply expressions afterwards if they should be applied - if (skipApply && stillApplyExpressions) { - UpdateExpression(); - } - proxy.Apply(); - } - + void FixedUpdate() { if (openSeeIKTarget.fixedUpdate) { RunUpdates(); @@ -2033,11 +856,8 @@ public class OpenSeeVRMDriver : MonoBehaviour { } void Update() { - fakeTimeTime = Time.time; if (inited && lastSmoothing != smoothAmount) { - #if WINDOWS_BUILD OVRLipSync.SendSignal(context, OVRLipSync.Signals.VisemeSmoothing, smoothAmount, 0); - #endif lastSmoothing = smoothAmount; } if (!openSeeIKTarget.fixedUpdate) { @@ -2046,7 +866,6 @@ public class OpenSeeVRMDriver : MonoBehaviour { } void DestroyContext() { - #if WINDOWS_BUILD active = false; lock (this) { if (context != 0) { @@ -2056,27 +875,9 @@ public class OpenSeeVRMDriver : MonoBehaviour { context = 0; } } - #endif } void OnDestroy() { DestroyContext(); } - - public void SetAnimateJawBone(bool value) { - animateJawBone = value; - } - - public void SetSmartWinkThreshold(float v) { - smartWinkThreshold = v; - } - - public void SetGazeSmoothing(float v) { - gazeSmoothing = v; - } - - public void SetVisemeNormalization(bool v) { - visemeNormalization = v; - } - } \ No newline at end of file diff --git a/Examples/OpenSeeVRMExpression.cs b/Examples/OpenSeeVRMExpression.cs index 5565c04..fc625ba 100644 --- a/Examples/OpenSeeVRMExpression.cs +++ b/Examples/OpenSeeVRMExpression.cs @@ -6,7 +6,6 @@ namespace OpenSee { public class OpenSeeVRMExpression : MonoBehaviour { - public OpenSee openSee; public OpenSeeExpression openSeeExpression; public VRMBlendShapeProxy vrmBlendShapeProxy; public string expressionNeutral = "neutral"; @@ -16,6 +15,7 @@ public class OpenSeeVRMExpression : MonoBehaviour public string expressionJoy = "shocked"; private BlendShapeKey lastKey; + private string lastExpression = ""; void Start() { @@ -26,52 +26,27 @@ public class OpenSeeVRMExpression : MonoBehaviour if (openSeeExpression == null || vrmBlendShapeProxy == null) { return; } - float rightEyeOpen = 1f; - float leftEyeOpen = 1f; - if (openSee != null) { - var openSeeData = openSee.trackingData; - if (openSeeData == null || openSeeData.Length < 1) - return; - int idx = -1; - int i = 0; - foreach (var item in openSeeData) { - if (item.id == openSeeExpression.faceId) - idx = i; - i++; - } - if (idx > -1) { - rightEyeOpen = openSeeData[idx].rightEyeOpen; - leftEyeOpen = openSeeData[idx].leftEyeOpen; - } - } - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Neutral), 0f); - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Fun), 0f); - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Sorrow), 0f); - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Angry), 0f); - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Joy), 0f); - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Blink_R), 0f); - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Blink_L), 0f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Neutral), 0f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Fun), 0f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Sorrow), 0f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Angry), 0f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Joy), 0f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_R), 0f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_L), 0f); if (openSeeExpression.expression == expressionFun) { - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Fun), 1f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Fun), 1f); return; } else if (openSeeExpression.expression == expressionSorrow) { - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Sorrow), 1f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Sorrow), 1f); return; } else if (openSeeExpression.expression == expressionAngry) { - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Angry), 1f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Angry), 1f); return; } else if (openSeeExpression.expression == expressionJoy) { - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Joy), 1f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Joy), 1f); return; - } else { - /*if (rightEyeOpen < 0.05) { - vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_R), 1f); - } - if (leftEyeOpen < 0.05) { - vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Blink_L), 1f); - }*/ } - vrmBlendShapeProxy.ImmediatelySetValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Neutral), 1f); + vrmBlendShapeProxy.ImmediatelySetValue(new BlendShapeKey(BlendShapePreset.Neutral), 1f); } } diff --git a/Examples/OpenSeeWebcamInfo.cs b/Examples/OpenSeeWebcamInfo.cs deleted file mode 100644 index 6663f28..0000000 --- a/Examples/OpenSeeWebcamInfo.cs +++ /dev/null @@ -1,270 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Net; -using System.Runtime.InteropServices; -using System.Text; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace OpenSee { - -[Serializable] -public enum OpenSeeWebcamType { Unknown = -1, DirectShow, Blackmagic }; - -[Serializable] -public enum OpenSeeWebcamFormat { Any = 0, Unknown = 1, ARGB = 100, XRGB, I420 = 200, NV12, YV12, Y800, YVYU = 300, YUY2, UYVY, HDYC, MJPEG = 400, H264 }; - -[Serializable] -public struct OpenSeeWebcamCapability { - public int id; - - // DirectShow - public int minCX; - public int minCY; - public int maxCX; - public int maxCY; - public int granularityCX; - public int granularityCY; - public int minInterval; - public int maxInterval; - public int rating; - public OpenSeeWebcamFormat format; - - // Blackmagic - public int bmTimescale; - public int bmFrameduration; - public int bmModecode; -} - -[Serializable] -public class OpenSeeWebcam { - public OpenSeeWebcamType type = OpenSeeWebcamType.Unknown; - public int id; - public string name; - - // DirectShow - public string path; - - // Blackmagic - public long bmId; - public int bmFlags; - - // General - public OpenSeeWebcamCapability[] caps; - - public List prettyCaps = null; - - private List> splitCaps = null; - - bool ge(bool a, bool b) { - return a || (!a && !b); - } - - private int CompareCaps(OpenSeeWebcamCapability a, OpenSeeWebcamCapability b) { - int aRes = a.minCX * a.minCY; - int bRes = b.minCX * b.minCY; - bool aGoodFps = a.minInterval <= 670000; - bool bGoodFps = a.minInterval <= 670000; - bool aGoodRes = aRes >= 850000 && aRes <= 2200000; - bool bGoodRes = bRes >= 850000 && bRes <= 2200000; - if (a.rating < b.rating && ge(aGoodFps, bGoodFps) && ge(aGoodRes, bGoodRes)) - return -1; - if (a.rating > b.rating && ge(bGoodFps, aGoodFps) && ge(bGoodRes, aGoodRes)) - return 1; - if (aRes > bRes && ge(aGoodFps, bGoodFps) && ge(aGoodRes, bGoodRes)) - return -1; - if (aRes < bRes && ge(bGoodFps, aGoodFps) && ge(bGoodRes, aGoodRes)) - return 1; - if (a.minInterval < b.minInterval) - return -1; - if (a.minInterval > b.minInterval) - return 1; - return 0; - } - - private string GetPrettyCapability(OpenSeeWebcamCapability cap) { - float fps = 10000000f / (float)cap.minInterval; - string prettyCap = cap.minCX + "x" + cap.minCY + ", " + fps.ToString("0.##") + "fps (" + cap.format.ToString() + ")"; - return prettyCap; - } - - public List GetPrettyCapabilities() { - if (splitCaps != null && prettyCaps != null) - return prettyCaps; - - splitCaps = new List>(); - - for (int i = 0; i < caps.Length; i++) { - if (caps[i].minCX == caps[i].maxCX && caps[i].minCY == caps[i].maxCY) - splitCaps.Add(new Tuple(caps[i], i)); - else { - OpenSeeWebcamCapability min = caps[i]; - OpenSeeWebcamCapability max = caps[i]; - min.maxCX = min.minCX; - min.maxCY = min.minCY; - max.minCX = max.maxCX; - max.minCY = max.maxCY; - splitCaps.Add(new Tuple(min, i)); - splitCaps.Add(new Tuple(max, i)); - } - } - - splitCaps.Sort((a, b) => CompareCaps(a.Item1, b.Item1)); - - prettyCaps = new List(); - if (type == OpenSeeWebcamType.DirectShow) - prettyCaps.Add("Default settings"); - foreach (var cap in splitCaps) { - prettyCaps.Add(GetPrettyCapability(cap.Item1)); - } - - return prettyCaps; - } - - public OpenSeeWebcamCapability GetCapabilityByPrettyIndex(int index) { - int dshowOffset = 0; - if (type == OpenSeeWebcamType.DirectShow) { - if (index == 0) { - OpenSeeWebcamCapability cap = new OpenSeeWebcamCapability(); - cap.id = -1; - cap.format = OpenSeeWebcamFormat.Any; - cap.minInterval = 10000000 / 60; - return cap; - } - dshowOffset = 1; - } - - if (splitCaps == null || index >= splitCaps.Count + dshowOffset || index < 0) - throw new InvalidOperationException("Invalid capability index."); - - return caps[splitCaps[index - dshowOffset].Item2]; - } -} - -[DefaultExecutionOrder(-50)] -public class OpenSeeWebcamInfo : MonoBehaviour { - #region DllImport - // DirectShow - [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "create_capture")] - private static extern System.IntPtr create_capture_x64(); - - [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")] - private static extern int get_json_length_x64(System.IntPtr cap); - - [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")] - private static extern void get_json_x64(System.IntPtr cap, [Out] StringBuilder namebuffer, int bufferlength); - - [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy_capture")] - private static extern void destroy_capture_x64(System.IntPtr cap); - - [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "create_capture")] - private static extern System.IntPtr create_capture_x86(); - - [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")] - private static extern int get_json_length_x86(System.IntPtr cap); - - [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")] - private static extern void get_json_x86(System.IntPtr cap, [Out] StringBuilder namebuffer, int bufferlength); - - [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy_capture")] - private static extern void destroy_capture_x86(System.IntPtr cap); - - // Blackmagic - [DllImport("libminibmcapture64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")] - private static extern int bm_get_json_length_x64(); - - [DllImport("libminibmcapture64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")] - private static extern void bm_get_json_x64([Out] StringBuilder namebuffer, int bufferlength); - - [DllImport("libminibmcapture32", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json_length")] - private static extern int bm_get_json_length_x86(); - - [DllImport("libminibmcapture32", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_json")] - private static extern void bm_get_json_x86([Out] StringBuilder namebuffer, int bufferlength); - #endregion - - [Serializable] - public class OpenSeeWebcamList { - public List list; - } - - public List cameras; - public bool dumpJson = false; - - private static bool dumpJsonStatic = false; - - static private string ListCameraDetails_x64() { - System.IntPtr cap = create_capture_x64(); - int length = get_json_length_x64(cap); - StringBuilder buffer = new StringBuilder(length); - get_json_x64(cap, buffer, length); - destroy_capture_x64(cap); - return buffer.ToString(); - } - - static private string ListCameraDetails_x86() { - System.IntPtr cap = create_capture_x86(); - int length = get_json_length_x86(cap); - StringBuilder buffer = new StringBuilder(length); - get_json_x86(cap, buffer, length); - destroy_capture_x86(cap); - return buffer.ToString(); - } - - static private string ListBlackMagicDetails_x64() { - int length = bm_get_json_length_x64(); - StringBuilder buffer = new StringBuilder(length); - bm_get_json_x64(buffer, length); - return buffer.ToString(); - } - - static private string ListBlackMagicDetails_x86() { - int length = bm_get_json_length_x86(); - StringBuilder buffer = new StringBuilder(length); - bm_get_json_x86(buffer, length); - return buffer.ToString(); - } - - static public List ListCameraDetails(bool includeBlackMagic) { - string jsonData = null; - string bmJsonData = null; - if (Environment.Is64BitProcess) { - jsonData = ListCameraDetails_x64(); - if (includeBlackMagic) - bmJsonData = ListBlackMagicDetails_x64(); - } else { - jsonData = ListCameraDetails_x86(); - if (includeBlackMagic) - bmJsonData = ListBlackMagicDetails_x86(); - } - if (dumpJsonStatic) { - UnityEngine.Debug.Log("Camera JSON: " + jsonData); - if (includeBlackMagic) - UnityEngine.Debug.Log("Blackmagic JSON: " + bmJsonData); - } - List details = JsonUtility.FromJson("{\"list\":" + jsonData + "}").list; - foreach (var cam in details) - cam.type = OpenSeeWebcamType.DirectShow; - if (includeBlackMagic) { - List bmDetails = JsonUtility.FromJson("{\"list\":" + bmJsonData + "}").list; - foreach (var cam in bmDetails) - cam.type = OpenSeeWebcamType.Blackmagic; - details.AddRange(bmDetails); - } - return details; - } - - void Start() { - Initialize(false); - } - - public void Initialize(bool includeBlackMagic) { - dumpJsonStatic = dumpJson; - cameras = ListCameraDetails(includeBlackMagic); - foreach (var camera in cameras) - camera.GetPrettyCapabilities(); - } -} -} \ No newline at end of file diff --git a/Examples/OpenSeeWebcamInfo.cs.meta b/Examples/OpenSeeWebcamInfo.cs.meta deleted file mode 100644 index 8fef5a0..0000000 --- a/Examples/OpenSeeWebcamInfo.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2e9598f1218283b418c7e72604be0335 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: -50 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Images/0_Parade_Parade_0_171.jpg b/Images/0_Parade_Parade_0_171.jpg deleted file mode 100644 index 8bd86ce..0000000 Binary files a/Images/0_Parade_Parade_0_171.jpg and /dev/null differ diff --git a/Images/3DDFA_V2.jpg b/Images/3DDFA_V2.jpg deleted file mode 100644 index 4a2f5fe..0000000 Binary files a/Images/3DDFA_V2.jpg and /dev/null differ diff --git a/Images/3DDFA_V2_800.jpg b/Images/3DDFA_V2_800.jpg deleted file mode 100644 index 14b0816..0000000 Binary files a/Images/3DDFA_V2_800.jpg and /dev/null differ diff --git a/Images/EmiFace.png b/Images/EmiFace.png deleted file mode 100644 index ed7e7af..0000000 Binary files a/Images/EmiFace.png and /dev/null differ diff --git a/Images/OSF.png b/Images/OSF.png deleted file mode 100644 index b8e23d8..0000000 Binary files a/Images/OSF.png and /dev/null differ diff --git a/Images/Points.png b/Images/Points.png deleted file mode 100644 index 0bc8a07..0000000 Binary files a/Images/Points.png and /dev/null differ diff --git a/Images/Raw1.png b/Images/Raw1.png deleted file mode 100644 index 8cad909..0000000 Binary files a/Images/Raw1.png and /dev/null differ diff --git a/Images/Raw2.png b/Images/Raw2.png deleted file mode 100644 index dcbba46..0000000 Binary files a/Images/Raw2.png and /dev/null differ diff --git a/Images/Raw3.png b/Images/Raw3.png deleted file mode 100644 index bfa98ac..0000000 Binary files a/Images/Raw3.png and /dev/null differ diff --git a/Images/Raw4.png b/Images/Raw4.png deleted file mode 100644 index e3e06e8..0000000 Binary files a/Images/Raw4.png and /dev/null differ diff --git a/Images/Results1.png b/Images/Results1.png deleted file mode 100644 index 6a2617f..0000000 Binary files a/Images/Results1.png and /dev/null differ diff --git a/Images/Results2.png b/Images/Results2.png deleted file mode 100644 index 5efd304..0000000 Binary files a/Images/Results2.png and /dev/null differ diff --git a/Images/Results3.png b/Images/Results3.png deleted file mode 100644 index 4d85211..0000000 Binary files a/Images/Results3.png and /dev/null differ diff --git a/Images/Results4.png b/Images/Results4.png deleted file mode 100644 index 355488f..0000000 Binary files a/Images/Results4.png and /dev/null differ diff --git a/Licenses/DShowCapture.txt b/Licenses/DShowCapture.txt deleted file mode 100644 index 48555c3..0000000 --- a/Licenses/DShowCapture.txt +++ /dev/null @@ -1,505 +0,0 @@ -Modified by Emiliana_vt -https://github.com/emilianavt/libdshowcapture - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/Licenses/ThunderSVM.txt b/Licenses/ThunderSVM.txt deleted file mode 100644 index 8dada3e..0000000 --- a/Licenses/ThunderSVM.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/Licenses/libminibmcapture.txt b/Licenses/libminibmcapture.txt deleted file mode 100644 index 05aa705..0000000 --- a/Licenses/libminibmcapture.txt +++ /dev/null @@ -1,19 +0,0 @@ -zlib License - -libminibmcapture (C) 2020 noorus - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. \ No newline at end of file diff --git a/Licenses/scikit-image.txt b/Licenses/scikit-image.txt deleted file mode 100644 index 108806d..0000000 --- a/Licenses/scikit-image.txt +++ /dev/null @@ -1,81 +0,0 @@ -Copyright (C) 2019, the scikit-image team -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - 3. Neither the name of skimage nor the names of its contributors may be - used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -skimage/_shared/version_requirements.py:_check_version - - Copyright (c) 2013 The IPython Development Team - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -skimage/_shared/version_requirements.py:is_installed: - - Original Copyright (C) 2009-2011 Pierre Raybaut - - 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. diff --git a/README.md b/README.md index 4d17be5..a389c61 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,20 @@ -![OSF.png](https://raw.githubusercontent.com/emilianavt/OpenSeeFace/master/Images/OSF.png) - # Overview -**Note**: This is a tracking library, **not** a stand-alone avatar puppeteering program. I'm also working on [VSeeFace](https://www.vseeface.icu/), which allows animating [VRM](https://vrm.dev/en/how_to_make_vrm/) and [VSFAvatar](https://www.youtube.com/watch?v=jhQ8DF87I5I) 3D models by using OpenSeeFace tracking. [VTube Studio](https://denchisoft.com/) uses OpenSeeFace for webcam based tracking to animate Live2D models. A renderer for the Godot engine can be found [here](https://github.com/virtual-puppet-project/vpuppr). - This project implements a facial landmark detection model based on MobileNetV3. As Pytorch 1.3 CPU inference speed on Windows is very low, the model was converted to ONNX format. Using [onnxruntime](https://github.com/microsoft/onnxruntime) it can run at 30 - 60 fps tracking a single face. There are four models, with different speed to tracking quality trade-offs. If anyone is curious, the name is a silly pun on the open seas and seeing faces. There's no deeper meaning. -An up to date sample video can be found [here](https://www.youtube.com/watch?v=AaNap_ud_3I&vq=hd1080), showing the default tracking model's performance under different noise and light levels. +Thanks to [@Virtual_Deat](https://twitter.com/Virtual_Deat) and [@ENiwatori](https://twitter.com/eniwatori) for helping me test things. Additional thanks to [@ArgamaWitch](https://twitter.com/ArgamaWitch) for further testing. -# Tracking quality +[Unity sample video](https://twitter.com/emiliana_vt/status/1210622149314203648) | [Sample video](https://www.youtube.com/watch?v=AOPHiAp9DBE) | [Sample video](https://www.youtube.com/watch?v=-cBSuHGdBWQ) | [Model comparison](https://www.youtube.com/watch?v=yMcJszUy7FA) -Since the landmarks used by OpenSeeFace are a bit different from those used by other approaches (they are close to iBUG 68, with two less points in the mouth corners and quasi-3D face contours instead of face contours that follow the visible outline) it is hard to numerically compare its accuracy to that of other approaches found commonly in scientific literature. The tracking performance is also more optimized for making landmarks that are useful for animating an avatar than for exactly fitting the face image. For example, as long as the eye landmarks show whether the eyes are opened or closed, even if their location is somewhat off, they can still be useful for this purpose. - -From general observation, OpenSeeFace performs well in adverse conditions (low light, high noise, low resolution) and keeps tracking faces through a very wide range of head poses with relatively high stability of landmark positions. Compared to MediaPipe, OpenSeeFace landmarks remain more stable in challenging conditions and it accurately represents a wider range of mouth poses. However, tracking of the eye region can be less accurate. - -I ran OpenSeeFace on a sample clip from the video presentation for [3D Face Reconstruction with Dense Landmarks](https://microsoft.github.io/DenseLandmarks/) by Wood et al. to compare it to MediaPipe and their approach. You can watch the result [here](https://www.vseeface.icu/assets/media/OSFMediaPipe3DFR.mp4). +These sample videos use older versions of the tracking models. # Usage -A sample Unity project for VRM based avatar animation can be found [here](https://github.com/emilianavt/OpenSeeFaceSample). - -The face tracking itself is done by the `facetracker.py` Python 3.7 script. It is a commandline program, so you should start it manually from cmd or write a batch file to start it. If you downloaded a release and are on Windows, you can run the `facetracker.exe` inside the `Binary` folder without having Python installed. You can also use the `run.bat` inside the `Binary` folder for a basic demonstration of the tracker. +The face tracking itself is done by the `facetracker.py` Python 3.7 script. It is a commandline program, so you should start it manually from cmd or write a batch file to start it. The script will perform the tracking on webcam input or video file and send the tracking data over UDP. This design also allows tracking to be done on a separate PC from the one who uses the tracking information. This can be useful to enhance performance and to avoid accidentially revealing camera footage. @@ -38,8 +28,6 @@ A simple demonstration can be achieved by creating a new scene in Unity, adding python facetracker.py --visualize 3 --pnp-points 1 --max-threads 4 -c video.mp4 -__Note__: If dependencies were installed using [poetry](https://python-poetry.org/), the commands have to be executed from a `poetry shell` or have to be prefixed with `poetry run`. - This way the tracking script will output its own tracking visualization while also demonstrating the transmission of tracking data to Unity. The included `OpenSeeLauncher` component allows starting the face tracker program from Unity. It is designed to work with the pyinstaller created executable distributed in the binary release bundles. It provides three public API functions: @@ -91,34 +79,15 @@ To save both the trained model and the captured training data, type in a filenam # Models -Four pretrained face landmark models are included. Using the `--model` switch, it is possible to select them for tracking. The given fps values are for running the model on a single face video on a single CPU core. Lowering the frame rate would reduce CPU usage by a corresponding degree. +Four pretrained models are included. Using the `--model` switch, it is possible to select them for tracking. The given fps values are for running the model on a single face video on a single CPU core. Lowering the frame rate would reduce CPU usage by a corresponding degree. -* Model **-1**: This model is for running on toasters, so it's a very very fast and very low accuracy model. (213fps without gaze tracking) * Model **0**: This is a very fast, low accuracy model. (68fps) -* Model **1**: This is a slightly slower model with better accuracy. (59fps) -* Model **2**: This is a slower model with good accuracy. (50fps) -* Model **3** (default): This is the slowest and highest accuracy model. (44fps) +* Model **1**: This is a slightly slower model with better accuracy based on MobileNetV3. (59fps) +* Model **2**: This is a slower model with good accuracy based on ShuffleNetV2. (50fps) +* Model **3** (default): This is the slowest and highest accuracy model. It is based on MobileNetV3. (44fps) FPS measurements are from running on one core of my CPU. -Pytorch weights for use with `model.py` can be found [here](https://mega.nz/file/vvYXlYQT#h7FpEg4tmOCJNxjpsDEw0JomJIkVGKwrt4OUV0RNDDU). Some unoptimized ONNX models can be found [here](https://github.com/emilianavt/OpenSeeFace/issues/48). - -# Results - -## Landmarks - -![Results1.png](https://raw.githubusercontent.com/emilianavt/OpenSeeFace/master/Images/Results1.png) - -![Results2.png](https://raw.githubusercontent.com/emilianavt/OpenSeeFace/master/Images/Results2.png) - -More samples: [Results3.png](https://raw.githubusercontent.com/emilianavt/OpenSeeFace/master/Images/Results3.png), [Results4.png](https://raw.githubusercontent.com/emilianavt/OpenSeeFace/master/Images/Results4.png) - -## Face detection - -The landmark model is quite robust with respect to the size and orientation of the faces, so the custom face detection model gets away with rougher bounding boxes than other approaches. It has a favorable speed to accuracy ratio for the purposes of this project. - -![EmiFace.png](https://raw.githubusercontent.com/emilianavt/OpenSeeFace/master/Images/EmiFace.png) - # Release builds The builds in the release section of this repository contain a `facetracker.exe` inside a `Binary` folder that was built using `pyinstaller` and contains all required dependencies. @@ -129,8 +98,9 @@ When distributing it, you should also distribute the `Licenses` folder along wit The release builds contain a custom build of ONNX Runtime without telemetry. -# Dependencies (Python 3.6 - 3.9) +# Dependencies +* Python 3.7 * ONNX Runtime * OpenCV * Pillow @@ -140,22 +110,6 @@ The required libraries can be installed using pip: pip install onnxruntime opencv-python pillow numpy -Alternatively poetry can be used to -install all dependencies for this project in a separate virtual env: - - poetry install - -# Dependencies - -* onnxruntime -* OpenCV -* Pillow -* Numpy - -The required libraries can be installed using pip: - - pip install onnxruntime opencv-python pillow numpy - # References ## Training dataset @@ -181,17 +135,6 @@ Additional training has been done on the WFLW dataset after reducing it to 66 po For the training the gaze and blink detection model, the [MPIIGaze](https://www.mpi-inf.mpg.de/departments/computer-vision-and-machine-learning/research/gaze-based-human-computer-interaction/appearance-based-gaze-estimation-in-the-wild/) dataset was used. Additionally, around 125000 synthetic eyes generated with [UnityEyes](https://www.cl.cam.ac.uk/research/rainbow/projects/unityeyes/) were used during training. -It should be noted that additional custom data was also used during the training process and that the reference landmarks from the original datasets have been modified in certain ways to address various issues. It is likely not possible to reproduce these models with just the original LS3D-W and WFLW datasets, however the additional data is not redistributable. - -The heatmap regression based face detection model was trained on random 224x224 crops from the WIDER FACE dataset. - - @inproceedings{yang2016wider, - Author = {Yang, Shuo and Luo, Ping and Loy, Chen Change and Tang, Xiaoou}, - Booktitle = {IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, - Title = {WIDER FACE: A Face Detection Benchmark}, - Year = {2016} - } - ## Algorithm The algorithm is inspired by: @@ -204,7 +147,7 @@ The algorithm is inspired by: The MobileNetV3 code was taken from [here](https://github.com/rwightman/gen-efficientnet-pytorch). -For all training a modified version of [Adaptive Wing Loss](https://github.com/tankrant/Adaptive-Wing-Loss) was used. +For all training after the first model, a modified version of [Adaptive Wing Loss](https://github.com/tankrant/Adaptive-Wing-Loss) was used. * [Adaptive Wing Loss for Robust Face Alignment via Heatmap Regression](https://arxiv.org/abs/1904.07399) by Xinyao Wang, Liefeng Bo, Li Fuxin @@ -221,18 +164,6 @@ Face detection is done using a custom heatmap regression based face detection mo RetinaFace detection is based on [this](https://github.com/biubug6/Pytorch_Retinaface) implementation. The pretrained model was modified to remove unnecessary landmark detection and converted to ONNX format for a resolution of 640x640. -# Thanks! - -Many thanks to everyone who helped me test things! - -* [@Virtual_Deat](https://twitter.com/Virtual_Deat), who also inspired me to start working on this. -* [@ENiwatori](https://twitter.com/eniwatori) and family. -* [@ArgamaWitch](https://twitter.com/ArgamaWitch) -* [@AngelVayuu](https://twitter.com/AngelVayuu) -* [@DapperlyYours](https://twitter.com/DapperlyYours) -* [@comdost_art](https://twitter.com/comdost_art) -* [@Ponoki_Chan](https://twitter.com/Ponoki_Chan) - # License The code and models are distributed under the BSD 2-clause license. diff --git a/Source/ThunderSVMWrapper.cpp b/Source/ThunderSVMWrapper.cpp deleted file mode 100644 index 6743ebb..0000000 --- a/Source/ThunderSVMWrapper.cpp +++ /dev/null @@ -1,222 +0,0 @@ -// ThunderSVMWrapper.cpp : Defines the exported functions for the DLL. -// - -#include "pch.h" -#include "framework.h" -#include "ThunderSVMWrapper.h" -#include "thundersvm/thundersvm.h" -#include "thundersvm/model/svmmodel.h" -#include "thundersvm/model/svc.h" -#include - -using namespace std; - -extern "C" void __cdecl print_log(const char *str) { - return; -} - -struct problem { - int r; - int c; - DataSet::node2d x; - vector y; - DataSet dataset; -}; - -struct SVMWrapper { - SVC *model; - int cols; - int classes; - double *means; - double *sdevs; - SvmParam param; - struct problem problem; -}; - -typedef struct svm_node svmnode; - -void make_svmnode_array(DataSet::node2d &dataset, float features[], int rows, int cols, double *means, double *sdevs, int rescale) { - double row_factor = 1.0 / (double)rows; - if (rescale) { - for (int c = 0; c < cols; c++) { - means[c] = 0; - sdevs[c] = 0; - } - for (int r = 0; r < rows; r++) { - for (int c = 0; c < cols; c++) { - means[c] += (double)features[r * cols + c]; - } - } - for (int c = 0; c < cols; c++) { - means[c] *= row_factor; - } - for (int r = 0; r < rows; r++) { - for (int c = 0; c < cols; c++) { - double sq_diff = ((double)features[r * cols + c] - means[c]); - sq_diff *= sq_diff; - sdevs[c] += sq_diff; - } - } - for (int c = 0; c < cols; c++) { - sdevs[c] *= row_factor; - sdevs[c] = sqrt(sdevs[c]); - sdevs[c] = 1.0 / sdevs[c]; - } - } - - for (int r = 0; r < rows; r++) { - dataset[r] = vector(cols); - int idx = 0; - for (int c = 0; c < cols; c++) { - dataset[r][c].index = c + 1; - dataset[r][c].value = (float)((features[r * cols + c] - means[c]) * sdevs[c]); - } - } -} - -void make_problem(struct problem &problem, float features[], float labels[], int rows, int cols, double *means, double *sdevs) { - problem.r = rows; - problem.c = cols; - problem.y = vector(rows); - for (int i = 0; i < rows; i++) - problem.y[i] = (double)labels[i]; - problem.x = DataSet::node2d(rows); - make_svmnode_array(problem.x, features, rows, cols, means, sdevs, 1); - problem.dataset = DataSet(problem.x, cols, problem.y); -} - -void destroy_problem(struct problem &problem) { - problem.y.clear(); - problem.x.clear(); -} - -extern "C" { - __declspec(dllexport) void *__cdecl trainModel(float features[], float labels[], float weights[], int rows, int cols, int classes, int probability, float C) { - if (!(rows > 0 && cols > 0)) - return NULL; - - //svm_set_print_string_function(print_log); - - struct SVMWrapper *sw = new SVMWrapper(); - sw->cols = cols; - sw->classes = classes; - sw->means = new double[cols]; - sw->sdevs = new double[cols]; - - sw->param.svm_type = SvmParam::C_SVC; - sw->param.kernel_type = SvmParam::RBF; - sw->param.degree = 3; - sw->param.gamma = 1.0 / (double)cols; - sw->param.coef0 = 0; - sw->param.nu = 0.5; - sw->param.C = C; - sw->param.epsilon = 0.001; - sw->param.p = 0.1; - sw->param.probability = probability; - sw->param.nr_weight = 0; - sw->param.weight_label = NULL; - sw->param.weight = NULL; - - if (weights != NULL) { - sw->param.nr_weight = classes; - sw->param.weight_label = new int[classes]; - sw->param.weight = new double[classes]; - for (int i = 0; i < classes; i++) { - sw->param.weight_label[i] = i; - sw->param.weight[i] = (double)weights[i]; - } - } - - make_problem(sw->problem, features, labels, rows, cols, sw->means, sw->sdevs); - sw->model = new SVC();//svm_train(sw->problem, &sw->param); - sw->model->train(sw->problem.dataset, sw->param); - - if (weights != NULL) { - delete sw->param.weight_label; - delete sw->param.weight; - } - - return sw; - } - - __declspec(dllexport) void __cdecl predict(void *ptr, float features[], float predictions[], double probabilities[], int rows) { - struct SVMWrapper *sw = (struct SVMWrapper *)ptr; - int cols = sw->cols; - - DataSet::node2d instances = DataSet::node2d(rows); - make_svmnode_array(instances, features, rows, sw->cols, sw->means, sw->sdevs, 0); - vector predicted = sw->model->predict(instances, -1); - instances.clear(); - for (int r = 0; r < rows; r++) - predictions[r] = (float)predicted[r]; - if (probabilities != NULL && sw->param.probability) { - vector probs = sw->model->get_prob_predict(); - for (int r = 0; r < rows; r++) - for (int c = 0; c < sw->classes; c++) - probabilities[c + r * sw->classes] = probs[c + r * sw->classes]; - } - predicted.clear(); - - return; - } - - __declspec(dllexport) void *__cdecl loadModel(char *filename, int cols, int classes, double means[], double sdevs[]) { - struct SVMWrapper *sw = new SVMWrapper(); - sw->cols = cols; - sw->model = new SVC(); - sw->model->load_from_file(filename); - sw->classes = classes; - sw->means = new double[cols]; - sw->sdevs = new double[cols]; - for (int c = 0; c < cols; c++) { - sw->means[c] = means[c]; - sw->sdevs[c] = sdevs[c]; - } - return sw; - } - - __declspec(dllexport) void *__cdecl loadModelString(char *modelString, int cols, int classes, double means[], double sdevs[]) { - struct SVMWrapper *sw = new SVMWrapper(); - sw->cols = cols; - sw->model = new SVC(); - sw->model->load_from_string(modelString); - sw->classes = classes; - sw->means = new double[cols]; - sw->sdevs = new double[cols]; - for (int c = 0; c < cols; c++) { - sw->means[c] = means[c]; - sw->sdevs[c] = sdevs[c]; - } - return sw; - } - - __declspec(dllexport) void __cdecl getScales(void *ptr, double means[], double sdevs[]) { - struct SVMWrapper *sw = (struct SVMWrapper *)ptr; - int cols = sw->cols; - for (int c = 0; c < cols; c++) { - means[c] = sw->means[c]; - sdevs[c] = sw->sdevs[c]; - } - } - - __declspec(dllexport) const char *__cdecl saveModelString(void *ptr) { - struct SVMWrapper *sw = (struct SVMWrapper *)ptr; - string model = sw->model->save_to_string(); - return _strdup(model.c_str()); - } - - __declspec(dllexport) int __cdecl saveModel(void *ptr, char *filename) { - struct SVMWrapper *sw = (struct SVMWrapper *)ptr; - sw->model->save_to_file(string(filename)); - return 1; - } - - __declspec(dllexport) void __cdecl destroyModel(void *ptr) { - struct SVMWrapper *sw = (struct SVMWrapper *)ptr; - delete sw->means; - delete sw->sdevs; - delete sw->model; - destroy_problem(sw->problem); - delete sw; - } -} \ No newline at end of file diff --git a/Unity/OpenSee.cs b/Unity/OpenSee.cs index 009972f..ef5f00a 100644 --- a/Unity/OpenSee.cs +++ b/Unity/OpenSee.cs @@ -24,8 +24,6 @@ public class OpenSee : MonoBehaviour { [Tooltip("This contains the actual tracking data")] public OpenSeeData[] trackingData = null; - public bool listening { get; private set; } = false; - [HideInInspector] public float maxFit3DError = 100f; @@ -41,9 +39,9 @@ public class OpenSee : MonoBehaviour { public float rightEyeOpen; [Tooltip("This field tells you how likely it is that the left eye is open.")] public float leftEyeOpen; - [Tooltip("This field contains the rotation of the right eyeball.")] + [Tooltip("This field tells you how likely it is that the right eye is open.")] public Quaternion rightGaze; - [Tooltip("This field contains the rotation of the left eyeball.")] + [Tooltip("This field tells you how likely it is that the left eye is open.")] public Quaternion leftGaze; [Tooltip("This field tells you if 3D points have been successfully estimated from the 2D points. If this is false, do not rely on pose or 3D data.")] public bool got3DPoints; @@ -213,7 +211,6 @@ public class OpenSee : MonoBehaviour { void performReception() { EndPoint senderRemote = new IPEndPoint(IPAddress.Any, 0); - listening = true; while (!stopReception) { try { int receivedBytes = socket.ReceiveFrom(buffer, SocketFlags.None, ref senderRemote); diff --git a/Unity/OpenSeeExpression.cs b/Unity/OpenSeeExpression.cs index 1c05057..11c4f30 100644 --- a/Unity/OpenSeeExpression.cs +++ b/Unity/OpenSeeExpression.cs @@ -13,18 +13,6 @@ public class OpenSeeExpression : MonoBehaviour [Header("Settings")] [Tooltip("This is the source of face tracking data. If it is not set, any OpenSee component on the current object is used.")] public OpenSee openSee; - [Tooltip("When enabled ThunderSVM is used instead of LibSVM, which is usually faster, but may cause issues on some systems.")] - public bool useThunderSVM = false; - [Header("Simple mode")] - [Tooltip("When enabled, some simple heuristics will be used to detect expressions, rather than an SVM model. Outputs one of: neutral, fun, angry, surprise")] - public bool simpleMode = false; - [Tooltip("This smoothing factor is applied to the features used for simple expression detection.")] - [Range(0f, 1f)] - public float simpleSmoothing = 0.6f; - [Tooltip("This smoothing factor is applied to the features used for simple expression detection.")] - [Range(0f, 5f)] - public float simpleSensitivity = 1f; - [Header("Calibration")] [Tooltip("This specifies which expression calibration data should be collected for.")] public string calibrationExpression = "neutral"; [Tooltip("This specifies the id of the face for which data should be collected and predictions should be made. Face ids depend only on the order of first detection and locations of the faces.")] @@ -62,7 +50,7 @@ public class OpenSeeExpression : MonoBehaviour [Tooltip("These settings can be used to train an expression detection model on a subset of points.")] public PointSelection pointSelection; [Header("Information")] - [Tooltip("This is the number of expressions for which calibration data was collected. The maximum number is 10.")] + [Tooltip("This is the of expressions for which calibration data was collected. The maximum number is 10.")] public int expressionNumber = 0; [Tooltip("This is the percentage of necessary training data collected for the current expression.")] public float percentRecorded = 0.0f; @@ -83,44 +71,6 @@ public class OpenSeeExpression : MonoBehaviour public string confusionMatrixString = ""; [Tooltip("This shows any accuracy warnings that resulted from the last training run.")] public string[] warnings = null; - - private float lastMouthCorner = 0f; - private float lastEyebrows = 0f; - private bool hadFun = false; - private bool hadAngry = false; - private bool hadSurprised = false; - float AdjustThreshold(bool active) { - if (active) - return 0.8f; - else - return 1f; - } - void ThresholdDetection() { - lastMouthCorner = lastMouthCorner * simpleSmoothing + (openSeeData.features.MouthCornerUpDownLeft + openSeeData.features.MouthCornerUpDownRight) * 0.5f * (1f - simpleSmoothing); - lastEyebrows = lastEyebrows * simpleSmoothing + (openSeeData.features.EyebrowUpDownLeft + openSeeData.features.EyebrowUpDownRight) * 0.5f * (1f - simpleSmoothing); - if (lastMouthCorner * simpleSensitivity < -0.2f * AdjustThreshold(hadFun)) { - expression = "fun"; - hadFun = true; - hadSurprised = false; - hadAngry = false; - } else if (lastEyebrows * simpleSensitivity > 0.2f * AdjustThreshold(hadSurprised)) { - expression = "surprise"; - hadFun = false; - hadSurprised = true; - hadAngry = false; - } else if (lastEyebrows * simpleSensitivity < -0.25f * AdjustThreshold(hadAngry) && lastMouthCorner * simpleSensitivity > -0.3f * (2f - AdjustThreshold(hadAngry))) { - expression = "angry"; - hadFun = false; - hadSurprised = false; - hadAngry = true; - } else { - expression = "neutral"; - hadFun = false; - hadSurprised = false; - hadAngry = false; - } - expressionTime = Time.time; - } [Serializable] public class PointSelection { @@ -154,7 +104,6 @@ public class OpenSeeExpression : MonoBehaviour private string[] classLabels = null; private int[] indices = null; private PointSelection pointSelection; - private bool thunderSVM = false; //private bool newModel = false; static public void LoadSerialized(byte[] modelBytes, out Dictionary> expressions, out SVMModel model, out string[] classLabels, out int[] indices, ref PointSelection pointSelection) { @@ -166,9 +115,6 @@ public class OpenSeeExpression : MonoBehaviour oser = formatter.Deserialize(gzipStream) as OpenSeeExpressionRepresentation; } expressions = oser.expressions; - /*if (oser.thunderSVM) - model = new ThunderSVMModel(oser.modelBytes); - else*/ model = new SVMModel(oser.modelBytes); classLabels = oser.classLabels; indices = oser.indices; @@ -191,7 +137,6 @@ public class OpenSeeExpression : MonoBehaviour oser.classLabels = classLabels; oser.indices = indices; oser.pointSelection = pointSelection; - oser.thunderSVM = model is ThunderSVMModel; //oser.newModel = true; IFormatter formatter = new BinaryFormatter(); @@ -364,10 +309,7 @@ public class OpenSeeExpression : MonoBehaviour } ResetInfo(); expressions = new Dictionary>(); - if (useThunderSVM) - model = new ThunderSVMModel(); - else - model = new SVMModel(); + model = new SVMModel(); rnd = new System.Random(); } @@ -421,10 +363,7 @@ public class OpenSeeExpression : MonoBehaviour return false; } modelReady = false; - if (model is SVMModel && useThunderSVM) - model = new ThunderSVMModel(); - else if (model is ThunderSVMModel && !useThunderSVM) - model = new SVMModel(); + //model = new SVMModel(); SelectPoints(); List keys = new List(); List accuracyWarnings = new List(); @@ -438,13 +377,13 @@ public class OpenSeeExpression : MonoBehaviour samples += list.Count; } else { if (list != null && list.Count > 20) { - Debug.Log("[Training warning] Expression " + key + " has little data and might be inaccurate. (" + list.Count + ")"); - accuracyWarnings.Add("Expression " + key + " has little data and might be inaccurate. (" + list.Count + ")"); + Debug.Log("[Training warning] Expression " + key + " has little data and might be inaccurate."); + accuracyWarnings.Add("Expression " + key + " has little data and might be inaccurate."); samples += list.Count; keys.Add(key); } else { - Debug.Log("[Training warning] Skipping expression " + key + " due to lack of collected data. (" + list.Count + ")"); - accuracyWarnings.Add("Skipping expression " + key + " due to lack of collected data. (" + list.Count + ")"); + Debug.Log("[Training warning] Skipping expression " + key + " due to lack of collected data."); + accuracyWarnings.Add("Skipping expression " + key + " due to lack of collected data."); continue; } } @@ -462,16 +401,11 @@ public class OpenSeeExpression : MonoBehaviour if (weightMap != null) { weights = new float[classLabels.Length]; for (int i = 0; i < classLabels.Length; i++) { - if (weightMap.ContainsKey(classLabels[i])) - weights[i] = weightMap[classLabels[i]]; - else - weights[i] = 1f; + weights[i] = weightMap[classLabels[i]]; Debug.Log("[Training info] Adding weight " + weights[i] + " for " + classLabels[i] + "."); } } - Debug.Log("[Training info] Preparing trainig data."); - int train_split = maxSamples * 3 / 4; int test_split = maxSamples - train_split; int rows_train = classes * train_split; @@ -521,7 +455,6 @@ public class OpenSeeExpression : MonoBehaviour i_test++; } } - Debug.Log("[Training info] Preparation complete."); int probability = 0; if (enableProbabilityTraining) probability = 1; @@ -541,24 +474,17 @@ public class OpenSeeExpression : MonoBehaviour } warnings = accuracyWarnings.ToArray(); modelReady = true; - Debug.Log("[Training info] Trained model."); return true; } public bool PredictExpression() { - if (openSee == null) - return false; - if (!simpleMode && !(modelReady && model.Ready())) { + if (openSee == null || !(modelReady && model.Ready())) { ResetInfo(); return false; } openSeeData = openSee.GetOpenSeeData(faceId); if (openSeeData == null || openSeeData.time <= lastCapture) return false; - if (simpleMode) { - ThresholdDetection(); - return true; - } float[] faceData = GetData(openSeeData); float[] predictionData = new float[cols]; for (int i = 0; i < cols; i++) @@ -706,7 +632,7 @@ public class OpenSeeExpression : MonoBehaviour SaveToFile(); if (!predict) expression = ""; - else if (simpleMode || modelReady) + else if (modelReady) PredictExpression(); else predict = false; diff --git a/Unity/OpenSeeIKTarget.cs b/Unity/OpenSeeIKTarget.cs index 4f775f8..d2dfc5e 100644 --- a/Unity/OpenSeeIKTarget.cs +++ b/Unity/OpenSeeIKTarget.cs @@ -2,24 +2,15 @@ namespace OpenSee { -[DefaultExecutionOrder(-1)] public class OpenSeeIKTarget : MonoBehaviour { [Header("Settings")] [Tooltip("This is the source of face tracking data.")] public OpenSee openSee; - [Tooltip("When this is set to another game object, its kinematic interpolation component will get updated from values of this.")] - public OpenSeeKinematicInterpolation kinematicInterpolation; - [Tooltip("When set, the this object will follow the specified transform instead and automatically recalibrate based on it.")] - public Transform externalTarget = null; - [Tooltip("This can be used to skip the first few tracking frames.")] - public int skipFirst = 5; [Tooltip("When set to true, the next rotation and translation values will be set as zero rotation and zero translation.")] public bool calibrate = true; [Tooltip("This sets which face id to look for in the OpenSee data.")] public int faceId = 0; - [Tooltip("When enabled, the IK target will not move up and down.")] - public bool preventVerticalMotion = false; [Tooltip("When this is enabled, rotations and movement are mirrored.")] public bool mirrorMotion = false; [Tooltip("Often, the translation vector's scale is too high. Setting this somewhere between 0.05 to 0.3 seems stabilize things, but it also reduces the range of motion.")] @@ -35,34 +26,13 @@ public class OpenSeeIKTarget : MonoBehaviour public bool driftBack = false; [Tooltip("This sets the strength of the drifting effect. At 0 there is now drifting, while the IK target will be static at 1.")] public float driftFactor = 0.005f; - [Tooltip("This sets the minimum angle difference between two poses after which the pose will be considered an outlier.")] - [Range(0, 360)] - public float outlierThresholdAngle = 35f; - [Tooltip("This sets the number of seconds for which angle outliers are ignored before being accepted. Setting this to zero will disable outlier skipping.")] - public float outlierSkipPeriod = 0.4f; - [Tooltip("This sets the minimum distance difference between two poses after which the pose will be considered an outlier.")] - public float outlierThresholdDistance = 2f; - [Tooltip("This sets the number of seconds for which distance outliers are ignored before being accepted. Once this period elapses, automatic recalibration is triggered. Setting this to zero will disable outlier skipping.")] - public float outlierSkipPeriodDistance = 0.4f; - [Tooltip("If set to true, persistent positional outliers will cause automatic recalibration.")] - public bool outlierRecalibrate = false; - [Tooltip("If set to true, recalibration caused by positional outliers will keep the current position and rotation of the head.")] - public bool outlierKeepOffset = false; [Header("Information")] - [Tooltip("This is the number of received tracking frames.")] - public int trackingFrames = 0; [Tooltip("This is the current rotation calibration value as euler angles.")] public Vector3 rotationOffset = new Vector3(0f, 0f, -90f); [Tooltip("This is the current translation calibration.")] public Vector3 translationOffset = new Vector3(0f, 0f, 0f); [Tooltip("This is the average number of interpolated frames per received tracking data.")] public float averageInterpolations = 0f; - [Tooltip("This is the number of outlier skipped tracking data frames so far.")] - public int outlierSkips = 0; - [Tooltip("This is the number of distance outlier skipped tracking data frames so far.")] - public int outlierSkipsDistance = 0; - [Tooltip("This is the number of times a recalibration was triggered due to positional outliers.")] - public int outlierCalibrations = 0; private double updated = 0.0f; private Quaternion dR = Quaternion.Euler(0f, 0f, -90f); @@ -76,57 +46,18 @@ public class OpenSeeIKTarget : MonoBehaviour private Quaternion currentR; private Vector3 currentT; private bool lastMirror = false; - - private bool gotAccepted = false; - private Quaternion lastAccepted; - private bool skipped = false; - private float skipStartTime = -1f; - - private bool gotAcceptedPosition = false; - private Vector3 lastAcceptedPosition; - private bool skippedPosition = false; - private float skipStartTimePosition = -1f; - - private Transform lastExternalTarget = null; public void Calibrate() { calibrate = true; } - - public static Vector3 PrettyEuler(Vector3 last, Vector3 current) { - // Ew, but how would you do componentwise filtering/interpolation with quaternions? - if (Mathf.Abs(current.x - last.x) > Mathf.Abs((current.x - 360f) - last.x)) - current.x -= 360f; - else if (Mathf.Abs(current.x - last.x) > Mathf.Abs((current.x + 360f) - last.x)) - current.x += 360f; - if (Mathf.Abs(current.y - last.y) > Mathf.Abs((current.y - 360f) - last.y)) - current.y -= 360f; - else if (Mathf.Abs(current.y - last.y) > Mathf.Abs((current.y + 360f) - last.y)) - current.x += 360f; - if (Mathf.Abs(current.z - last.z) > Mathf.Abs((current.z - 360f) - last.z)) - current.z -= 360f; - else if (Mathf.Abs(current.z - last.z) > Mathf.Abs((current.z + 360f) - last.z)) - current.z += 360f; - return current; - } - - Vector3 FilterPos(Vector3 a, Vector3 b) { - return Vector3.Lerp(a, b, 1f - smooth); - } - - Quaternion FilterRot(Quaternion a, Quaternion b) { - return Quaternion.Lerp(a, b, 1f - smooth); - } void Interpolate() { if (!interpolate || interpolateState < 2) return; - float t = Mathf.Clamp((float)interpolationCount / avgInterps, 0f, 1.5f); - transform.localPosition = Vector3.SlerpUnclamped(lastT, currentT, t); - transform.localRotation = Quaternion.SlerpUnclamped(lastR, currentR, t); + float t = Mathf.Clamp((float)interpolationCount / avgInterps, 0f, 0.985f); + transform.localPosition = Vector3.Lerp(lastT, currentT, t); + transform.localRotation = Quaternion.Lerp(lastR, currentR, t); interpolationCount++; - //transform.localPosition = new Vector3(0.3f * ((Time.time/3f) % 3f) - 0.5f, 0.3f * Mathf.Sin(Mathf.Rad2Deg * ((Time.time/5f) % 3f)), 0f); - //transform.localRotation = Quaternion.identity * Quaternion.AngleAxis(20f * Mathf.Sin(Mathf.Rad2Deg * ((Time.time/5f) % 3f)) - 10f, Vector3.up); } Quaternion MirrorQuaternion(Quaternion q) { @@ -139,100 +70,20 @@ public class OpenSeeIKTarget : MonoBehaviour void RunUpdate() { var openSeeData = openSee.GetOpenSeeData(faceId); - Quaternion convertedQuaternion; - Vector3 t; - Vector3 convertedTranslation; - - if (externalTarget == null) { - if (openSeeData == null || openSeeData.fit3DError > openSee.maxFit3DError) - return; - if (openSeeData.time > updated) { - updated = openSeeData.time; - trackingFrames++; - if (trackingFrames < skipFirst) - return; - } else { - Interpolate(); - return; - } - - convertedQuaternion = new Quaternion(-openSeeData.rawQuaternion.y, -openSeeData.rawQuaternion.x, openSeeData.rawQuaternion.z, openSeeData.rawQuaternion.w); - t = openSeeData.translation; - t.x = -t.x; - t.z = -t.z; - convertedTranslation = new Vector3(t.x, t.y, t.z); + if (openSeeData == null || openSeeData.fit3DError > openSee.maxFit3DError) + return; + if (openSeeData.time > updated) { + updated = openSeeData.time; } else { - convertedQuaternion = externalTarget.localRotation; - convertedTranslation = externalTarget.localPosition; - t = convertedTranslation; - } - - // Check for angular outliers - if (gotAccepted) { - float angularDifference = Quaternion.Angle(lastAccepted, convertedQuaternion); - if (angularDifference >= outlierThresholdAngle) { - if (!skipped) { - if (outlierSkipPeriod >= 0.0000001f) { - skipStartTime = Time.time; - skipped = true; - } - } else { - if (Time.time > skipStartTime + outlierSkipPeriod) { - lastAccepted = convertedQuaternion; - skipped = false; - } - } - } else { - skipped = false; - lastAccepted = convertedQuaternion; - } - } else { - lastAccepted = convertedQuaternion; - skipped = false; - } - gotAccepted = true; - if (skipped) { - outlierSkips += 1; + Interpolate(); return; } - - // Check for positional outliers - bool keepOffset = false; - if (gotAcceptedPosition) { - float distance = Vector3.Distance(t, lastAcceptedPosition); - if (distance > outlierThresholdDistance) { - if (!skippedPosition) { - if (outlierSkipPeriodDistance >= 0.0000001f) { - skipStartTimePosition = Time.time; - skippedPosition = true; - } - } else { - if (Time.time > skipStartTimePosition + outlierSkipPeriodDistance) { - lastAcceptedPosition = t; - skippedPosition = false; - if (outlierRecalibrate) { - calibrate = true; - keepOffset = outlierKeepOffset; - outlierCalibrations += 1; - } - } - } - } else { - skippedPosition = false; - lastAcceptedPosition = t; - } - } else { - skippedPosition = false; - lastAcceptedPosition = t; - } - gotAcceptedPosition = true; - if (skippedPosition) { - outlierSkipsDistance += 1; - return; - } - - calibrate = calibrate || (externalTarget != lastExternalTarget); - lastExternalTarget = externalTarget; + + Quaternion convertedQuaternion = new Quaternion(-openSeeData.rawQuaternion.y, -openSeeData.rawQuaternion.x, openSeeData.rawQuaternion.z, openSeeData.rawQuaternion.w); + Vector3 t = openSeeData.translation; + t.x = -t.x; + t.z = -t.z; + Vector3 convertedTranslation = new Vector3(t.x, t.y, t.z); if (calibrate) { dR = convertedQuaternion; @@ -240,8 +91,6 @@ public class OpenSeeIKTarget : MonoBehaviour dT = t; rotationOffset = new Vector3(dR.eulerAngles.x, dR.eulerAngles.y, dR.eulerAngles.z); translationOffset = new Vector3(dT.x, dT.y, dT.z); - lastAcceptedPosition = translationOffset; - skippedPosition = false; } if (mirrorMotion != lastMirror || (mirrorMotion && calibrate)) { @@ -249,53 +98,35 @@ public class OpenSeeIKTarget : MonoBehaviour dT = MirrorTranslation(dT); lastMirror = mirrorMotion; } - if (calibrate && keepOffset) { - dR = Quaternion.Inverse(Quaternion.Inverse(transform.localRotation) * Quaternion.Inverse(dR)); - dT -= transform.localPosition; - } calibrate = false; if (mirrorMotion) { convertedQuaternion = MirrorQuaternion(convertedQuaternion); t = MirrorTranslation(t); } - + if (interpolateState > 1) avgInterps = Mathf.Lerp(avgInterps, (float)interpolationCount, 0.15f); interpolationCount = 0; averageInterpolations = avgInterps; - - lastT = transform.localPosition; - lastR = transform.localRotation; + + lastT = currentT; + lastR = currentR; if (interpolateState > 0) { - currentT = FilterPos(transform.localPosition, (t - dT) * translationScale); - currentR = FilterRot(transform.localRotation, convertedQuaternion * dR); + currentT = Vector3.Lerp(currentT, (t - dT) * translationScale, 1f - smooth); + currentR = Quaternion.Lerp(transform.localRotation, convertedQuaternion * dR, 1f - smooth); } else { currentT = (t - dT) * translationScale; currentR = convertedQuaternion * dR; } if (interpolateState < 2) interpolateState++; - + if (interpolate) { Interpolate(); } else { - transform.localPosition = FilterPos(transform.localPosition, (t - dT) * translationScale); - transform.localRotation = FilterRot(transform.localRotation, convertedQuaternion * dR); - } - - if (preventVerticalMotion) { - currentT.y = 0f; - Vector3 pos = transform.localPosition; - pos.y = 0f; - transform.localPosition = pos; - } - - if (kinematicInterpolation != null && kinematicInterpolation.gameObject != gameObject) { - if (interpolate) - kinematicInterpolation.UpdateKI(updated, currentT, currentR); - else - kinematicInterpolation.UpdateKI(updated, transform.localPosition, transform.localRotation); + transform.localPosition = Vector3.Lerp(transform.localPosition, (t - dT) * translationScale, 1f - smooth); + transform.localRotation = Quaternion.Lerp(transform.localRotation, convertedQuaternion * dR, 1f - smooth); } if (driftBack) { @@ -310,10 +141,6 @@ public class OpenSeeIKTarget : MonoBehaviour translationOffset = new Vector3(dT.x, dT.y, dT.z); } } - - public void SetPreventVerticalMotion(bool v) { - preventVerticalMotion = v; - } void FixedUpdate() { diff --git a/Unity/OpenSeeIKTarget.cs.meta b/Unity/OpenSeeIKTarget.cs.meta index dd50d92..2507d88 100644 --- a/Unity/OpenSeeIKTarget.cs.meta +++ b/Unity/OpenSeeIKTarget.cs.meta @@ -4,7 +4,7 @@ MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] - executionOrder: -5 + executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: diff --git a/Unity/OpenSeeInterpolation.cs b/Unity/OpenSeeInterpolation.cs deleted file mode 100644 index 91980b9..0000000 --- a/Unity/OpenSeeInterpolation.cs +++ /dev/null @@ -1,232 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace OpenSee { - public class InterpolatedMap where V : InterpolatedValue, new() { - private Dictionary map = new Dictionary(); - private float clamp = 1f; - private float smoothing = 0f; - private bool gotDefault = false; - private U defaultValue; - - public void Clear() { - map.Clear(); - } - - public void SetSmoothing(float smoothing) { - this.smoothing = smoothing; - foreach (var entry in map) { - if (entry.Value != null) - entry.Value.SetSmoothing(smoothing); - } - } - - public void SetClamp(float clamp) { - this.clamp = clamp; - foreach (var entry in map) { - if (entry.Value != null) - entry.Value.SetClamp(clamp); - } - } - - void Prepare(T key) { - if (!map.ContainsKey(key)) { - map.Add(key, new V()); - map[key].SetSmoothing(smoothing); - map[key].SetClamp(clamp); - } - } - - public void SetValue(T key, U v) { - Prepare(key); - map[key].SetValue(v); - } - - public void Store(T key, U v) { - Prepare(key); - map[key].UpdateValue(v); - } - - public void Store(T key, U v, double nowT) { - if (!map.ContainsKey(key)) { - map.Add(key, new V()); - map[key].SetSmoothing(smoothing); - map[key].SetClamp(clamp); - } - map[key].UpdateValue(v, nowT); - } - - public U GetDefault() { - if (gotDefault) - return defaultValue; - V tmp = new V(); - defaultValue = tmp.GetDefault(); - return defaultValue; - } - - public bool Check(T key) { - return map.ContainsKey(key); - } - - public U Get(T key) { - if (!map.ContainsKey(key)) - return GetDefault(); - return map[key].Interpolate(); - } - } - - abstract public class InterpolatedValue { - private float interpolateT = 0f; - private float updateT = 0f; - private double lastT = 0f; - private double currentT = 0f; - private float clamp = 1f; - private float smoothing = 0f; - private int gotData = 0; - - private bool haveDefault = false; - private V defaultValue; - - private bool valueSet = false; - private V dataValue; - private V dataValueLast; - - abstract public V ValueLerpUnclamped(V a, V b, float t); - abstract public V GetBuiltinDefault(); - - public void SetDefault(V defaultValue) { - this.defaultValue = defaultValue; - haveDefault = true; - } - - public void ResetDefault() { - haveDefault = false; - } - - public V GetDefault() { - if (haveDefault) - return defaultValue; - return GetBuiltinDefault(); - } - - public void SetSmoothing(float smoothing) { - this.smoothing = smoothing; - } - - public void SetClamp(float clamp) { - this.clamp = clamp; - } - - public void SetValue(V v) { - dataValueLast = v; - dataValue = v; - valueSet = true; - } - - public InterpolatedValue(float smoothing = 0f, float clamp = 1f) { - this.smoothing = smoothing; - this.clamp = clamp; - } - - public void UpdateValue(V v) { - UpdateValue(v, Time.realtimeSinceStartup); - } - - public void UpdateValue(V v, double nowT) { - if (nowT < 0f) - return; - lock (this) { - if (nowT < currentT || gotData == 0) { - // Reinitialize - gotData = 1; - updateT = Time.time; - lastT = 0f; - currentT = nowT; - dataValueLast = GetDefault(); - dataValue = ValueLerpUnclamped(v, dataValueLast, smoothing); - } else if (nowT == currentT) { - // Change value - dataValue = ValueLerpUnclamped(v, dataValueLast, smoothing); - } else { - // Regular operation - updateT = Time.time; - lastT = currentT; - currentT = nowT; - if (gotData < 2) - gotData++; - dataValueLast = dataValue; - dataValue = ValueLerpUnclamped(v, dataValueLast, smoothing); - } - } - } - - public V Interpolate() { - lock (this) { - interpolateT = Time.time; - if (gotData < 2) { - if (valueSet) - return dataValue; - else - return GetDefault(); - } - float t = Mathf.Min((interpolateT - updateT) / (float)(currentT - lastT), clamp); - return ValueLerpUnclamped(dataValueLast, dataValue, t); - } - } - } - - public class InterpolatedColor : InterpolatedValue { - public override Color ValueLerpUnclamped(Color a, Color b, float t) { - return Color.LerpUnclamped(a, b, t); - } - public override Color GetBuiltinDefault() { - return Color.clear; - } - } - - public class InterpolatedQuaternion : InterpolatedValue { - public override Quaternion ValueLerpUnclamped(Quaternion a, Quaternion b, float t) { - return Quaternion.SlerpUnclamped(a, b, t); - } - public override Quaternion GetBuiltinDefault() { - return Quaternion.identity; - } - } - - public class InterpolatedVector2 : InterpolatedValue { - public override Vector2 ValueLerpUnclamped(Vector2 a, Vector2 b, float t) { - return Vector2.LerpUnclamped(a, b, t); - } - public override Vector2 GetBuiltinDefault() { - return Vector2.zero; - } - } - - public class InterpolatedVector3 : InterpolatedValue { - public override Vector3 ValueLerpUnclamped(Vector3 a, Vector3 b, float t) { - return Vector3.LerpUnclamped(a, b, t); - } - public override Vector3 GetBuiltinDefault() { - return Vector3.zero; - } - } - - public class InterpolatedVector4 : InterpolatedValue { - public override Vector4 ValueLerpUnclamped(Vector4 a, Vector4 b, float t) { - return Vector4.LerpUnclamped(a, b, t); - } - public override Vector4 GetBuiltinDefault() { - return Vector4.zero; - } - } - - public class InterpolatedFloat : InterpolatedValue { - public override float ValueLerpUnclamped(float a, float b, float t) { - return Mathf.LerpUnclamped(a, b, t); - } - public override float GetBuiltinDefault() { - return 0f; - } - } -} diff --git a/Unity/OpenSeeInterpolation.cs.meta b/Unity/OpenSeeInterpolation.cs.meta deleted file mode 100644 index a5eda33..0000000 --- a/Unity/OpenSeeInterpolation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d61e11f1b6900a7419383be1377f191b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/OpenSeeKinematicInterpolation.cs b/Unity/OpenSeeKinematicInterpolation.cs deleted file mode 100644 index 7b347a8..0000000 --- a/Unity/OpenSeeKinematicInterpolation.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace OpenSee { - -public class OpenSeeKinematicInterpolation : MonoBehaviour -{ - public float interpolateClamp = 1f; - - private Vector3 lastPos; - private Vector3 lastPosV; - private double lastT; - - private Vector3 currentPos; - private Vector3 currentPosV; - private double currentT = 0f; - - private Vector3 lastRot = Vector3.zero; - private Vector3 lastRotV; - - private Vector3 currentRot; - private Vector3 currentRotV; - - private float dT; - private Vector3 coeffPosA; - private Vector3 coeffPosB; - private Vector3 coeffRotA; - private Vector3 coeffRotB; - - private double updateT; - private double interpolateT; - private int ready = 0; - - public void UpdateKI(double newT, Vector3 newPos, Quaternion newRot) { - Interpolate(); - if (newT - currentT > 3f) - ready = 0; - - currentPos = transform.localPosition; - currentRot = OpenSeeIKTarget.PrettyEuler(currentRot, transform.localRotation.eulerAngles); - float dTNow = (float)(interpolateT - updateT); - if (interpolateT - updateT > 0 || ready < 1) { - currentPosV = (currentPos - lastPos) / dT; - currentRotV = (currentRot - lastRot) / dT; - } else { - currentPosV = Vector3.zero; - currentRotV = Vector3.zero; - } - - lastPos = currentPos; - lastPosV = currentPosV; - lastRot = currentRot; - lastRotV = currentRotV; - lastT = currentT; - - currentPos = newPos; - currentRot = OpenSeeIKTarget.PrettyEuler(lastRot, newRot.eulerAngles); - currentT = newT; - dT = (float)(currentT - lastT); - currentPosV = (currentPos - lastPos) / dT; - currentRotV = (currentRot - lastRot) / dT; - - float dTPow2 = Mathf.Pow(dT, 2); - float dTPow3 = Mathf.Pow(dT, 3); - coeffPosA = (- (2f*(currentPosV * dT + 2f * dT * lastPosV - 3f * currentPos + 3f * lastPos)) / dTPow2) / 2f; - coeffPosB = ((6f*(currentPosV * dT + dT * lastPosV - 2f * currentPos + 2f * lastPos)) / dTPow3)/6f; - coeffRotA = (- (2f*(currentRotV * dT + 2f * dT * lastRotV - 3f * currentRot + 3f * lastRot)) / dTPow2) / 2f; - coeffRotB = ((6f*(currentRotV * dT + dT * lastRotV - 2f * currentRot + 2f * lastRot)) / dTPow3)/6f; - - updateT = Time.time; - if (ready <= 2) - ready++; - } - - float InterpolateValue(float dTNow, float dTNowPow2, float dTNowPow3, float a, float b, float x1, float x2, float v1, float v2) { - return x1 + v1 * dTNow + dTNowPow2 * a + dTNowPow3 * b; - } - - void Interpolate() { - interpolateT = Time.time; - if (interpolateT == updateT || ready <= 2) - return; - float dTNow = (float)(interpolateT - updateT); - if (dTNow >= dT) { - transform.localPosition = Vector3.LerpUnclamped(lastPos, currentPos, Mathf.Min((float)(dTNow / dT), interpolateClamp)); - transform.localEulerAngles = Vector3.LerpUnclamped(lastRot, currentRot, Mathf.Min((float)(dTNow / dT), interpolateClamp)); - } else { - float dTNowPow2 = Mathf.Pow(dTNow, 2); - float dTNowPow3 = Mathf.Pow(dTNow, 3); - float x = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffPosA.x, coeffPosB.x, lastPos.x, currentPos.x, lastPosV.x, currentPosV.x); - float y = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffPosA.y, coeffPosB.y, lastPos.y, currentPos.y, lastPosV.y, currentPosV.y); - float z = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffPosA.z, coeffPosB.z, lastPos.z, currentPos.z, lastPosV.z, currentPosV.z); - transform.localPosition = new Vector3(x, y, z); - x = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffRotA.x, coeffRotB.x, lastRot.x, currentRot.x, lastRotV.x, currentRotV.x); - y = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffRotA.y, coeffRotB.y, lastRot.y, currentRot.y, lastRotV.y, currentRotV.y); - z = InterpolateValue(dTNow, dTNowPow2, dTNowPow3, coeffRotA.z, coeffRotB.z, lastRot.z, currentRot.z, lastRotV.z, currentRotV.z); - transform.localEulerAngles = new Vector3(x, y, z); - } - } - - public void Update() { - Interpolate(); - } -} - -} \ No newline at end of file diff --git a/Unity/OpenSeeKinematicInterpolation.cs.meta b/Unity/OpenSeeKinematicInterpolation.cs.meta deleted file mode 100644 index 1a31547..0000000 --- a/Unity/OpenSeeKinematicInterpolation.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a4112b4be90fc9e4baee9eade65378c3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: -1 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/OpenSeeLauncher.cs b/Unity/OpenSeeLauncher.cs index 2fa8280..29be64d 100644 --- a/Unity/OpenSeeLauncher.cs +++ b/Unity/OpenSeeLauncher.cs @@ -13,29 +13,17 @@ namespace OpenSee { public class OpenSeeLauncher : MonoBehaviour { #region DllImport - [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "create_capture")] - private static extern System.IntPtr create_capture_x64(); + [DllImport("escapi_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "countCaptureDevices")] + private static extern int countCaptureDevices_x64(); - [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_devices")] - private static extern int get_devices_x64(System.IntPtr cap); + [DllImport("escapi_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "getCaptureDeviceName")] + private static extern void getCaptureDeviceName_x64(int deviceno, [Out] StringBuilder namebuffer, int bufferlength); - [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_device")] - private static extern void get_device_x64(System.IntPtr cap, int deviceno, [Out] StringBuilder namebuffer, int bufferlength); + [DllImport("escapi_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "countCaptureDevices")] + private static extern int countCaptureDevices_x86(); - [DllImport("dshowcapture_x64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy_capture")] - private static extern void destroy_capture_x64(System.IntPtr cap); - - [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "create_capture")] - private static extern System.IntPtr create_capture_x86(); - - [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_devices")] - private static extern int get_devices_x86(System.IntPtr cap); - - [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "get_device")] - private static extern void get_device_x86(System.IntPtr cap, int deviceno, [Out] StringBuilder namebuffer, int bufferlength); - - [DllImport("dshowcapture_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy_capture")] - private static extern void destroy_capture_x86(System.IntPtr cap); + [DllImport("escapi_x86", CallingConvention = CallingConvention.Cdecl, EntryPoint = "getCaptureDeviceName")] + private static extern void getCaptureDeviceName_x86(int deviceno, [Out] StringBuilder namebuffer, int bufferlength); #endregion [Header("Settings")] @@ -51,21 +39,15 @@ public class OpenSeeLauncher : MonoBehaviour { public bool autoListCameras = false; [Tooltip("If this is enabled, no output from the tracker will be printed to the debug console. This cannot be changed while the tracker is running.")] public bool dontPrint = true; - [Tooltip("If enabled, the next available port within 500 starting after the one given on the OpenSee component will be used.")] - public bool dynamicPort = false; [Tooltip("The path to \"facetracker.exe\".")] public string exePath = "facetracker.exe"; [Tooltip("The path, where the .onnx model files can be found")] public string modelPath = "models\\"; [Tooltip("Additional options that should be passed to the face tracker.")] - public List commandlineOptions = new List(new string[] { "--silent", "1", "--max-threads", "1" }); - [Tooltip("This string will be appended at the end of the tracker options without quoting.")] - public string extraOptions = ""; - [Tooltip("If enabled, the tracker commandline option string will be logged with Debug.Log.")] - public bool logCommandline = false; - [Tooltip("IL2CPP doesn't support Proocess.Start. When this is enabled, OpenSeeLauncher will create the tracking process by calling the necessary API functions directly through the DLLs. In this case, reading the standard output from the process will not be supported and it will instead be send to the logfiles set in pinvokeStdOut and pinvokeStdErr in the persistent data directory. It will also retrieve the camera list directly through the libdshowcapture DLLs, so make sure it is part of your Unity project.")] + public List commandlineOptions = new List(new string[] { "--silent", "1", "--max-threads", "4" }); + [Tooltip("IL2CPP doesn't support Proocess.Start. When this is enabled, OpenSeeLauncher will create the tracking process by calling the necessary API functions directly through the DLLs. In this case, reading the standard output from the process will not be supported and it will instead be send to the logfiles set in pinvokeStdOut and pinvokeStdErr in the persistent data directory. It will also retrieve the camera list directly through the escapi DLLs, so make sure it is part of your Unity project.")] public bool usePinvoke = false; - [Tooltip("When this is enabled, even if usePinvoke is disabled, the camera list will be retrieved through libdshowcapture DLLs directly, which can be faster. Make sure the DLLs are in your Unity project.")] + [Tooltip("When this is enabled, even if usePinvoke is disabled, the camera list will be retrieved through escapi DLLs directly, which can be faster. Make sure the DLLs are in your Unity project.")] public bool usePinvokeListCameras = false; [Tooltip("This is the standard output log file's name in the persistent data directory.")] public string pinvokeStdOut = "output.txt"; @@ -83,30 +65,6 @@ public class OpenSeeLauncher : MonoBehaviour { private System.IntPtr processStdOut = System.IntPtr.Zero; private System.IntPtr processStdErr = System.IntPtr.Zero; private Job job = null; - - public void UnsetOption(string name, bool hasArgument) { - int count = 1; - if (hasArgument) - count++; - int found = -1; - int i = 0; - foreach (string arg in commandlineOptions) { - if (arg == name) { - found = i; - break; - } - i++; - } - if (found > -1) - commandlineOptions.RemoveRange(found, count); - } - - public void SetOption(string name, string argument) { - UnsetOption(name, argument != null); - commandlineOptions.Add(name); - if (argument != null) - commandlineOptions.Add(argument); - } private bool CheckSetup(bool requireTarget) { if (openSeeTarget == null) @@ -120,10 +78,10 @@ public class OpenSeeLauncher : MonoBehaviour { UnityEngine.Debug.LogError("Facetracker executable cannot be found."); return false; } - /*if (!Directory.Exists(modelPath)) { + if (!Directory.Exists(modelPath)) { UnityEngine.Debug.LogError("Model directory cannot be found."); return false; - }*/ + } if (requireTarget) { ip = openSeeTarget.listenAddress; if (!IPAddress.TryParse(ip, out address)) { @@ -153,38 +111,34 @@ public class OpenSeeLauncher : MonoBehaviour { return true; } - private string[] ListCameras_x64() { + private string[] EscapiListCameras_x64() { List cameras = new List(); - System.IntPtr cap = create_capture_x64(); - int count = get_devices_x64(cap); + int count = countCaptureDevices_x64(); for (int i = 0; i < count; i++) { StringBuilder namebuffer = new StringBuilder(2048); - get_device_x64(cap, i, namebuffer, 2048); + getCaptureDeviceName_x64(i, namebuffer, 2048); cameras.Add(namebuffer.ToString()); } - destroy_capture_x64(cap); return cameras.ToArray(); } - private string[] ListCameras_x86() { + private string[] EscapiListCameras_x86() { List cameras = new List(); - System.IntPtr cap = create_capture_x86(); - int count = get_devices_x86(cap); + int count = countCaptureDevices_x86(); for (int i = 0; i < count; i++) { StringBuilder namebuffer = new StringBuilder(2048); - get_device_x86(cap, i, namebuffer, 2048); + getCaptureDeviceName_x86(i, namebuffer, 2048); cameras.Add(namebuffer.ToString()); } - destroy_capture_x86(cap); return cameras.ToArray(); } public string[] ListCameras() { if (usePinvoke || usePinvokeListCameras) { if (Environment.Is64BitProcess) - return ListCameras_x64(); + return EscapiListCameras_x64(); else - return ListCameras_x86(); + return EscapiListCameras_x86(); } if (!CheckSetup(false)) @@ -223,48 +177,6 @@ public class OpenSeeLauncher : MonoBehaviour { return cameras; } - public float[] Benchmark(int threads) { - if (!CheckSetup(false)) - return null; - - StringBuilder stringBuilder; - ProcessStartInfo processStartInfo; - Process process; - - stringBuilder = new StringBuilder(); - - processStartInfo = new ProcessStartInfo(); - processStartInfo.CreateNoWindow = true; - processStartInfo.RedirectStandardOutput = true; - processStartInfo.RedirectStandardInput = true; - processStartInfo.RedirectStandardError = true; - processStartInfo.UseShellExecute = false; - processStartInfo.FileName = exePath; - processStartInfo.Arguments = "--benchmark 1 --priority 4 --max-threads " + threads.ToString(); - - process = new Process(); - process.StartInfo = processStartInfo; - process.EnableRaisingEvents = true; - process.OutputDataReceived += new DataReceivedEventHandler(delegate(object sender, DataReceivedEventArgs e) { - stringBuilder.Append(e.Data); - stringBuilder.Append("\n"); - }); - process.Start(); - job.AddProcess(process.Handle); - process.BeginOutputReadLine(); - process.WaitForExit(); - process.CancelOutputRead(); - - string[] lines = stringBuilder.ToString().Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); - float[] results = new float[lines.Length]; - - for (int i = 0; i < lines.Length; i++) { - results[i] = Single.Parse(lines[i]); - } - - return results; - } - // From: http://csharptest.net/529/how-to-correctly-escape-command-line-arguments-in-c/index.html private static string EscapeArguments(params string[] args) { @@ -297,32 +209,10 @@ public class OpenSeeLauncher : MonoBehaviour { List arguments = new List(); arguments.Add("--ip"); arguments.Add(ip); - - if (dynamicPort && !openSeeTarget.listening) { - System.Net.IPEndPoint[] inUse = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners(); - Array.Sort(inUse, delegate(System.Net.IPEndPoint a, System.Net.IPEndPoint b) { return a.Port.CompareTo(b.Port); }); - int port = openSeeTarget.listenPort + 1; - for (int i = 0; i < inUse.Length; i++) { - if (inUse[i].Port < port) - continue; - if (inUse[i].Port == port) { - if (port <= openSeeTarget.listenPort + 500 && port <= IPEndPoint.MaxPort) { - port++; - continue; - } else { - return false; - } - } - break; - } - openSeeTarget.listenPort = port; - } - arguments.Add("--port"); arguments.Add(openSeeTarget.listenPort.ToString()); arguments.Add("--model-dir"); arguments.Add(modelPath); - arguments.Add("--capture"); if (videoPath != "" && File.Exists(videoPath)) arguments.Add(videoPath); @@ -332,11 +222,6 @@ public class OpenSeeLauncher : MonoBehaviour { arguments.Add(argument); } string argumentString = EscapeArguments(arguments.ToArray()); - if (extraOptions != "") - argumentString = argumentString + " " + extraOptions; - - if (logCommandline) - UnityEngine.Debug.Log("Starting tracker: " + argumentString); StopTracker(); diff --git a/Unity/OpenSeeShowPoints.cs b/Unity/OpenSeeShowPoints.cs index 64c2fe1..bd7b1ea 100644 --- a/Unity/OpenSeeShowPoints.cs +++ b/Unity/OpenSeeShowPoints.cs @@ -7,7 +7,6 @@ namespace OpenSee { public class OpenSeeShowPoints : MonoBehaviour { public OpenSee openSee = null; public int faceId = 0; - public bool only30Points = false; public bool show3DPoints = true; public bool applyTranslation = false; public bool applyRotation = false; @@ -15,31 +14,17 @@ public class OpenSeeShowPoints : MonoBehaviour { public float minConfidence = 0.20f; public bool showGaze = true; public Material material; - public bool showLines = false; - public float lineWidth = 0.01f; - public Material lineMaterial; - public bool receiveShadows = false; - private OpenSee.OpenSeeData openSeeData; private GameObject[] gameObjects; - private LineRenderer[] lineRenderers; private GameObject centerBall; private double updated = 0.0; private int total = 70; - - private int[] lines = new int[]{/* Contour */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, -1, /* Eyebrows */ 18, 19, 20, 21, -1, 23, 24, 25, 26, -1, /* Nose */ 28, 29, 30, 33, 32, 33, 34, 35, -1, /* Eye */ 37, 38, 39, 40, 41, 36, /* Eye */ 43, 44, 45, 46, 47, 42, /* Mouth */ 49, 50, 51, 52, 62, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 58, 58, 62}; - - private HashSet pt30Set = new HashSet { 0, 2, 5, 8, 11, 14, 16, 17, 19, 21, 22, 24, 26, 27, 30, 33, 36, 37, 39, 40, 42, 43, 45, 46, 50, 55, 58, 60, 62, 64 }; - private int[] linesPt30Set = new int[]{/* Contour */ 2, -1, 5, -1, -1, 8, -1, -1, 11, -1, -1, 14, -1, -1, 16, -1, -1, /* Eyebrows */ 19, -1, 21, -1, -1, 24, -1, 26, -1, -1, /* Nose */ 30, -1, -1, 33, -1, -1, -1, -1, -1, /* Eye */ 37, 39, -1, 40, 36, -1, /* Eye */ 43, 45, -1, 46, 42, -1, /* Mouth */ -1, -1, 62, -1, -1, -1, -1, 58, -1, -1, 60, -1, 62, -1, 64, -1, 58, -1, 58, 62}; void Start () { if (openSee == null) { openSee = GetComponent(); } gameObjects = new GameObject[70]; - lineRenderers = new LineRenderer[68]; - if (lineMaterial == null) - showLines = false; if (!showGaze) total = 66; for (int i = 0; i < total; i++) { @@ -47,7 +32,6 @@ public class OpenSeeShowPoints : MonoBehaviour { gameObjects[i].name = "Point " + (i + 1); if (material != null) gameObjects[i].GetComponent().material = material; - gameObjects[i].GetComponent().receiveShadows = receiveShadows; gameObjects[i].layer = gameObject.layer; gameObjects[i].transform.SetParent(transform); gameObjects[i].transform.localScale = new Vector3(0.025f, 0.025f, 0.025f); @@ -55,42 +39,12 @@ public class OpenSeeShowPoints : MonoBehaviour { GameObject cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder); if (material != null) cylinder.GetComponent().material = material; - cylinder.GetComponent().receiveShadows = receiveShadows; cylinder.layer = gameObject.layer; cylinder.transform.SetParent(gameObjects[i].transform); cylinder.transform.localEulerAngles = new Vector3(90f, 0f, 0f); cylinder.transform.localPosition = new Vector3(0f, 0f, -4f); cylinder.transform.localScale = new Vector3(1f, 4f, 1f); } - if (only30Points && i < 66 && !pt30Set.Contains(i)) - gameObjects[i].SetActive(false); - } - for (int i = 0; i < 68; i++) { - if (i == 66) { - GameObject lineGameObject = new GameObject("LineGameObject"); - if (only30Points) - lineGameObject.transform.SetParent(gameObjects[50].transform); - else - lineGameObject.transform.SetParent(gameObjects[48].transform); - lineGameObject.layer = gameObject.layer; - lineRenderers[i] = lineGameObject.AddComponent(typeof(LineRenderer)) as LineRenderer; - } else if (i == 67) { - GameObject lineGameObject = new GameObject("LineGameObject"); - if (only30Points) - lineGameObject.transform.SetParent(gameObjects[55].transform); - else - lineGameObject.transform.SetParent(gameObjects[53].transform); - lineGameObject.layer = gameObject.layer; - lineRenderers[i] = lineGameObject.AddComponent(typeof(LineRenderer)) as LineRenderer; - } - else - lineRenderers[i] = gameObjects[i].AddComponent(typeof(LineRenderer)) as LineRenderer; - lineRenderers[i].useWorldSpace = true; - lineRenderers[i].generateLightingData = true; - lineRenderers[i].material = lineMaterial; - lineRenderers[i].receiveShadows = receiveShadows; - lineRenderers[i].widthMultiplier = lineWidth; - lineRenderers[i].positionCount = 2; } centerBall = GameObject.CreatePrimitive(PrimitiveType.Sphere); centerBall.name = "Center"; @@ -177,7 +131,6 @@ public class OpenSeeShowPoints : MonoBehaviour { for (int i = 0; i < 66; i++) { Renderer renderer = gameObjects[i].GetComponent(); - renderer.receiveShadows = receiveShadows; renderer.material.SetColor("_Color", Color.Lerp(Color.red, Color.green, openSeeData.confidence[i])); float x = openSeeData.points[i].x; float y = -openSeeData.points[i].y; @@ -188,37 +141,6 @@ public class OpenSeeShowPoints : MonoBehaviour { gameObjects[i].transform.localPosition = position; } } - for (int i = 0; i < 68; i++) { - if ((!only30Points && lines[i] == -1) || (only30Points && linesPt30Set[i] == -1)) - continue; - if (!showLines || lineMaterial == null) { - lineRenderers[i].enabled = false; - } else { - int a = i; - int b = lines[i]; - if (only30Points) { - b = linesPt30Set[i]; - if (i == 66) - a = 50; - if (i == 67) - a = 55; - } else { - if (i == 66) - a = 48; - if (i == 67) - a = 53; - } - Color color = Color.Lerp(Color.red, Color.green, Mathf.Lerp(0.5f, openSeeData.confidence[a], openSeeData.confidence[b])); - lineRenderers[i].enabled = true; - lineRenderers[i].widthMultiplier = lineWidth; - lineRenderers[i].receiveShadows = receiveShadows; - lineRenderers[i].material.SetColor("_Color", color); - lineRenderers[i].startColor = color; - lineRenderers[i].endColor = color; - lineRenderers[i].SetPosition(0, gameObjects[a].transform.position); - lineRenderers[i].SetPosition(1, gameObjects[b].transform.position); - } - } } } diff --git a/Unity/Plugins/SVMModel.cs b/Unity/Plugins/SVMModel.cs index fb9ca1b..705dd2c 100644 --- a/Unity/Plugins/SVMModel.cs +++ b/Unity/Plugins/SVMModel.cs @@ -6,61 +6,34 @@ using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; -using UnityEngine; namespace OpenSee { public class SVMModel { #region DllImport - [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, EntryPoint = "trainModel")] - private static extern System.IntPtr trainModelDll(float[] features, float[] labels, float[] weights, int rows, int cols, int classes, int probability, float C); - protected virtual System.IntPtr trainModel(float[] features, float[] labels, float[] weights, int rows, int cols, int classes, int probability, float C) { - Debug.Log("Training LibSVM"); - return trainModelDll(features, labels, weights, rows, cols, classes, probability, C); - } + [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl)] + private static extern System.IntPtr trainModel(float[] features, float[] labels, float[] weights, int rows, int cols, int classes, int probability, float C); - [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, EntryPoint = "predict")] - private static extern void predictDll(System.IntPtr model, float[] features, [Out] float[] predictions, [Out] double[] probabilities, int rows); - protected virtual void predict(System.IntPtr model, float[] features, [Out] float[] predictions, [Out] double[] probabilities, int rows) { - predictDll(model, features, predictions, probabilities, rows); - } + [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl)] + private static extern void predict(System.IntPtr model, float[] features, [Out] float[] predictions, [Out] double[] probabilities, int rows); - [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "loadModel")] - private static extern System.IntPtr loadModelDll([MarshalAs(UnmanagedType.LPStr)]string filename, int cols, int classes, double[] means, double[] sdevs); - protected virtual System.IntPtr loadModel([MarshalAs(UnmanagedType.LPStr)]string filename, int cols, int classes, double[] means, double[] sdevs) { - return loadModelDll(filename, cols, classes, means, sdevs); - } + [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + private static extern System.IntPtr loadModel([MarshalAs(UnmanagedType.LPStr)]string filename, int cols, int classes, double[] means, double[] sdevs); - [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "loadModelString")] - private static extern System.IntPtr loadModelStringDll([MarshalAs(UnmanagedType.LPStr)]string modelString, int cols, int classes, double[] means, double[] sdevs); - protected virtual System.IntPtr loadModelString([MarshalAs(UnmanagedType.LPStr)]string modelString, int cols, int classes, double[] means, double[] sdevs) { - Debug.Log("Loading LibSVM"); - return loadModelStringDll(modelString, cols, classes, means, sdevs); - } + [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + private static extern System.IntPtr loadModelString([MarshalAs(UnmanagedType.LPStr)]string modelString, int cols, int classes, double[] means, double[] sdevs); - [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, EntryPoint = "getScales")] - private static extern void getScalesDll(System.IntPtr model, [Out] double[] means, [Out] double[] sdevs); - protected virtual void getScales(System.IntPtr model, [Out] double[] means, [Out] double[] sdevs) { - getScalesDll(model, means, sdevs); - } + [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl)] + private static extern void getScales(System.IntPtr model, [Out] double[] means, [Out] double[] sdevs); - [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "saveModel")] - private static extern int saveModelDll(System.IntPtr model, [MarshalAs(UnmanagedType.LPStr)]string filename); - protected virtual int saveModel(System.IntPtr model, [MarshalAs(UnmanagedType.LPStr)]string filename) { - return saveModelDll(model, filename); - } + [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + private static extern int saveModel(System.IntPtr model, [MarshalAs(UnmanagedType.LPStr)]string filename); - [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "saveModelString")] - private static extern string saveModelStringDll(System.IntPtr model); - protected virtual string saveModelString(System.IntPtr model) { - return saveModelStringDll(model); - } + [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + private static extern string saveModelString(System.IntPtr model); - [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroyModel")] - private static extern void destroyModelDll(System.IntPtr model); - protected virtual void destroyModel(System.IntPtr model) { - destroyModelDll(model); - } + [DllImport("SVMModel", CallingConvention = CallingConvention.Cdecl)] + private static extern void destroyModel(System.IntPtr model); #endregion private bool haveModel = false; @@ -70,51 +43,51 @@ public class SVMModel { [Serializable] private class SVMModelRepresentation { - public string modelString; - public int cols; - public int maxClasses; - public double[] means; - public double[] sdevs; - } + private string modelString; + private int cols; + private int maxClasses; + private double[] means; + private double[] sdevs; - public System.IntPtr LoadSerialized(byte[] modelBytes, out int cols, out int maxClasses, bool compress) { - IFormatter formatter = new BinaryFormatter(); - MemoryStream memoryStream = new MemoryStream(modelBytes); - memoryStream.Position = 0; - SVMModelRepresentation smr; - if (compress) { - using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) { - smr = formatter.Deserialize(gzipStream) as SVMModelRepresentation; + static public System.IntPtr LoadSerialized(byte[] modelBytes, out int cols, out int maxClasses, bool compress) { + IFormatter formatter = new BinaryFormatter(); + MemoryStream memoryStream = new MemoryStream(modelBytes); + memoryStream.Position = 0; + SVMModelRepresentation smr; + if (compress) { + using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) { + smr = formatter.Deserialize(gzipStream) as SVMModelRepresentation; + } + } else { + smr = formatter.Deserialize(memoryStream) as SVMModelRepresentation; } - } else { - smr = formatter.Deserialize(memoryStream) as SVMModelRepresentation; + cols = smr.cols; + maxClasses = smr.maxClasses; + System.IntPtr model = loadModelString(smr.modelString, smr.cols, smr.maxClasses, smr.means, smr.sdevs); + return model; } - cols = smr.cols; - maxClasses = smr.maxClasses; - System.IntPtr model = loadModelString(smr.modelString, smr.cols, smr.maxClasses, smr.means, smr.sdevs); - return model; - } - public byte[] ToSerialized(System.IntPtr model, int cols, int maxClasses, bool compress) { - SVMModelRepresentation smr = new SVMModelRepresentation(); - smr.cols = cols; - smr.maxClasses = maxClasses; - smr.means = new double[cols]; - smr.sdevs = new double[cols]; - getScales(model, smr.means, smr.sdevs); - smr.modelString = saveModelString(model); + static public byte[] ToSerialized(System.IntPtr model, int cols, int maxClasses, bool compress) { + SVMModelRepresentation smr = new SVMModelRepresentation(); + smr.cols = cols; + smr.maxClasses = maxClasses; + smr.means = new double[cols]; + smr.sdevs = new double[cols]; + getScales(model, smr.means, smr.sdevs); + smr.modelString = saveModelString(model); - IFormatter formatter = new BinaryFormatter(); - MemoryStream memoryStream = new MemoryStream(); - if (compress) { - using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress)) { - formatter.Serialize(gzipStream, smr); - gzipStream.Flush(); + IFormatter formatter = new BinaryFormatter(); + MemoryStream memoryStream = new MemoryStream(); + if (compress) { + using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress)) { + formatter.Serialize(gzipStream, smr); + gzipStream.Flush(); + } + } else { + formatter.Serialize(memoryStream, smr); } - } else { - formatter.Serialize(memoryStream, smr); + return memoryStream.ToArray(); } - return memoryStream.ToArray(); } public void DestroyModel() { @@ -126,7 +99,7 @@ public class SVMModel { private void LoadModel(byte[] modelBytes, bool compress) { DestroyModel(); - model = LoadSerialized(modelBytes, out cols, out maxClasses, compress); + model = SVMModelRepresentation.LoadSerialized(modelBytes, out cols, out maxClasses, compress); haveModel = true; } @@ -137,7 +110,7 @@ public class SVMModel { private byte[] SaveModel(bool compress) { if (!haveModel) return null; - return ToSerialized(model, cols, maxClasses, compress); + return SVMModelRepresentation.ToSerialized(model, cols, maxClasses, compress); } public byte[] SaveModel() { @@ -170,9 +143,7 @@ public class SVMModel { maxClasses = max + 1; this.cols = cols; - float start = Time.realtimeSinceStartup; model = trainModel(features, labels, weights, rows, cols, maxClasses, probability, C); - Debug.Log("Training took: " + (Time.realtimeSinceStartup - start).ToString()); haveModel = true; return true; diff --git a/Unity/Plugins/ThunderSVMModel.cs b/Unity/Plugins/ThunderSVMModel.cs deleted file mode 100644 index 945260d..0000000 --- a/Unity/Plugins/ThunderSVMModel.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; -using System.Text; -using OpenSee; -using UnityEngine; - -public class ThunderSVMModel : SVMModel { - #region DllImport - [DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, EntryPoint = "trainModel")] - private static extern System.IntPtr trainModelDll(float[] features, float[] labels, float[] weights, int rows, int cols, int classes, int probability, float C); - protected override System.IntPtr trainModel(float[] features, float[] labels, float[] weights, int rows, int cols, int classes, int probability, float C) { - Debug.Log("Training ThunderSVM"); - return trainModelDll(features, labels, weights, rows, cols, classes, probability, C); - } - - [DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, EntryPoint = "predict")] - private static extern void predictDll(System.IntPtr model, float[] features, [Out] float[] predictions, [Out] double[] probabilities, int rows); - protected override void predict(System.IntPtr model, float[] features, [Out] float[] predictions, [Out] double[] probabilities, int rows) { - predictDll(model, features, predictions, probabilities, rows); - } - - [DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "loadModel")] - private static extern System.IntPtr loadModelDll([MarshalAs(UnmanagedType.LPStr)]string filename, int cols, int classes, double[] means, double[] sdevs); - protected override System.IntPtr loadModel([MarshalAs(UnmanagedType.LPStr)]string filename, int cols, int classes, double[] means, double[] sdevs) { - return loadModelDll(filename, cols, classes, means, sdevs); - } - - [DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "loadModelString")] - private static extern System.IntPtr loadModelStringDll([MarshalAs(UnmanagedType.LPStr)]string modelString, int cols, int classes, double[] means, double[] sdevs); - protected override System.IntPtr loadModelString([MarshalAs(UnmanagedType.LPStr)]string modelString, int cols, int classes, double[] means, double[] sdevs) { - Debug.Log("Loading ThunderSVM"); - return loadModelStringDll(modelString, cols, classes, means, sdevs); - } - - [DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, EntryPoint = "getScales")] - private static extern void getScalesDll(System.IntPtr model, [Out] double[] means, [Out] double[] sdevs); - protected override void getScales(System.IntPtr model, [Out] double[] means, [Out] double[] sdevs) { - getScalesDll(model, means, sdevs); - } - - [DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "saveModel")] - private static extern int saveModelDll(System.IntPtr model, [MarshalAs(UnmanagedType.LPStr)]string filename); - protected override int saveModel(System.IntPtr model, [MarshalAs(UnmanagedType.LPStr)]string filename) { - return saveModelDll(model, filename); - } - - [DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "saveModelString")] - private static extern string saveModelStringDll(System.IntPtr model); - protected override string saveModelString(System.IntPtr model) { - return saveModelStringDll(model); - } - - [DllImport("ThunderSVMWrapper", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroyModel")] - private static extern void destroyModelDll(System.IntPtr model); - protected override void destroyModel(System.IntPtr model) { - destroyModelDll(model); - } - #endregion - - public ThunderSVMModel() { - } - - public ThunderSVMModel(byte[] modelBytes) { - LoadModel(modelBytes); - } -} \ No newline at end of file diff --git a/Unity/Plugins/ThunderSVMWrapper.dll b/Unity/Plugins/ThunderSVMWrapper.dll deleted file mode 100644 index ff85cdb..0000000 Binary files a/Unity/Plugins/ThunderSVMWrapper.dll and /dev/null differ diff --git a/Unity/Plugins/ThunderSVMWrapper.dll.meta b/Unity/Plugins/ThunderSVMWrapper.dll.meta deleted file mode 100644 index 24d19ea..0000000 --- a/Unity/Plugins/ThunderSVMWrapper.dll.meta +++ /dev/null @@ -1,63 +0,0 @@ -fileFormatVersion: 2 -guid: 9c58dd9d1f0cf3140bd004d536712abb -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Editor: 0 - Exclude Linux64: 0 - Exclude OSXUniversal: 0 - Exclude Win: 1 - Exclude Win64: 0 - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 1 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Standalone: Linux64 - second: - enabled: 1 - settings: - CPU: x86_64 - - first: - Standalone: OSXUniversal - second: - enabled: 1 - settings: - CPU: x86_64 - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 1 - settings: - CPU: x86_64 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Plugins/dshowcapture_x64.dll b/Unity/Plugins/dshowcapture_x64.dll deleted file mode 100644 index 88e3752..0000000 Binary files a/Unity/Plugins/dshowcapture_x64.dll and /dev/null differ diff --git a/Unity/Plugins/dshowcapture_x64.dll.meta b/Unity/Plugins/dshowcapture_x64.dll.meta deleted file mode 100644 index 172154a..0000000 --- a/Unity/Plugins/dshowcapture_x64.dll.meta +++ /dev/null @@ -1,27 +0,0 @@ -fileFormatVersion: 2 -guid: dd0c04eb3445c3048bfaa964c6bcb16f -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Plugins/dshowcapture_x86.dll b/Unity/Plugins/dshowcapture_x86.dll deleted file mode 100644 index 55222da..0000000 Binary files a/Unity/Plugins/dshowcapture_x86.dll and /dev/null differ diff --git a/Unity/Plugins/dshowcapture_x86.dll.meta b/Unity/Plugins/dshowcapture_x86.dll.meta deleted file mode 100644 index b5dc9a7..0000000 --- a/Unity/Plugins/dshowcapture_x86.dll.meta +++ /dev/null @@ -1,27 +0,0 @@ -fileFormatVersion: 2 -guid: a504a0f747083b54c99d6e91731ccecc -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Plugins/libminibmcapture32.dll b/Unity/Plugins/libminibmcapture32.dll deleted file mode 100644 index 156b184..0000000 Binary files a/Unity/Plugins/libminibmcapture32.dll and /dev/null differ diff --git a/Unity/Plugins/libminibmcapture32.dll.meta b/Unity/Plugins/libminibmcapture32.dll.meta deleted file mode 100644 index fcc39c3..0000000 --- a/Unity/Plugins/libminibmcapture32.dll.meta +++ /dev/null @@ -1,27 +0,0 @@ -fileFormatVersion: 2 -guid: 51dc8f0c65df30d4daa188cdfd1dd220 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Plugins/libminibmcapture64.dll b/Unity/Plugins/libminibmcapture64.dll deleted file mode 100644 index a9139ba..0000000 Binary files a/Unity/Plugins/libminibmcapture64.dll and /dev/null differ diff --git a/Unity/Plugins/libminibmcapture64.dll.meta b/Unity/Plugins/libminibmcapture64.dll.meta deleted file mode 100644 index 2be2e1b..0000000 --- a/Unity/Plugins/libminibmcapture64.dll.meta +++ /dev/null @@ -1,27 +0,0 @@ -fileFormatVersion: 2 -guid: fcfc753ca92169e48aa69c1ecc1b0d64 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Plugins/thundersvm.dll b/Unity/Plugins/thundersvm.dll deleted file mode 100644 index 9c56754..0000000 Binary files a/Unity/Plugins/thundersvm.dll and /dev/null differ diff --git a/Unity/Plugins/thundersvm.dll.meta b/Unity/Plugins/thundersvm.dll.meta deleted file mode 100644 index b01d6bb..0000000 --- a/Unity/Plugins/thundersvm.dll.meta +++ /dev/null @@ -1,63 +0,0 @@ -fileFormatVersion: 2 -guid: e549e6cbc6a547748abc7f1b05bfa7b4 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Editor: 0 - Exclude Linux64: 0 - Exclude OSXUniversal: 0 - Exclude Win: 1 - Exclude Win64: 0 - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 1 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Standalone: Linux64 - second: - enabled: 1 - settings: - CPU: x86_64 - - first: - Standalone: OSXUniversal - second: - enabled: 1 - settings: - CPU: x86_64 - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 1 - settings: - CPU: x86_64 - userData: - assetBundleName: - assetBundleVariant: diff --git a/dshowcapture.py b/dshowcapture.py deleted file mode 100644 index 515125c..0000000 --- a/dshowcapture.py +++ /dev/null @@ -1,341 +0,0 @@ -import os -import platform -import sys -import numpy as np -from ctypes import * -from PIL import Image -import cv2 -import json - -def resolve(name): - f = os.path.join(os.path.dirname(__file__), name) - return f - -lib = None -bm_lib = None -bm_options = None -bm_enabled = False - -def set_bm_enabled(v): - global bm_enabled - bm_enabled = v - -def set_options(str): - global bm_options - bm_options = str - -def create_frame_buffer(width, height, factor): - buffer = bytearray(width * height * 4 * factor) - char_array = c_char * len(buffer) - return char_array.from_buffer(buffer) - -class DShowCapture(): - def __init__(self): - global lib - global bm_lib - global bm_options - global bm_enabled - if lib is None or bm_lib is None: - if platform.architecture()[0] == '32bit': - dll_path = resolve(os.path.join("dshowcapture", "dshowcapture_x86.dll")) - lib = cdll.LoadLibrary(dll_path) - if bm_enabled: - dll_path = resolve(os.path.join("dshowcapture", "libminibmcapture32.dll")) - bm_lib = cdll.LoadLibrary(dll_path) - else: - dll_path = resolve(os.path.join("dshowcapture", "dshowcapture_x64.dll")) - lib = cdll.LoadLibrary(dll_path) - if bm_enabled: - dll_path = resolve(os.path.join("dshowcapture", "libminibmcapture64.dll")) - bm_lib = cdll.LoadLibrary(dll_path) - - # DirectShow - lib.create_capture.restype = c_void_p - lib.get_devices.argtypes = [c_void_p] - lib.get_device.argtypes = [c_void_p, c_int, c_char_p, c_int] - lib.capture_device.argtypes = [c_void_p, c_int, c_int, c_int, c_int] - lib.capture_device_by_dcap.argtypes = [c_void_p, c_int, c_int, c_int, c_int, c_longlong] - lib.capture_device_default.argtypes = [c_void_p, c_int] - lib.get_width.argtypes = [c_void_p] - lib.get_height.argtypes = [c_void_p] - lib.get_fps.argtypes = [c_void_p] - lib.get_flipped.argtypes = [c_void_p] - lib.get_colorspace.argtypes = [c_void_p] - lib.get_colorspace_internal.argtypes = [c_void_p] - lib.capturing.argtypes = [c_void_p] - lib.get_frame.argtypes = [c_void_p, c_int, c_char_p, c_int] - lib.get_size.argtypes = [c_void_p] - lib.stop_capture.argtypes = [c_void_p] - lib.get_json_length.argtypes = [c_void_p] - lib.get_json.argtypes = [c_void_p, c_char_p, c_int] - lib.destroy_capture.argtypes = [c_void_p] - - # Blackmagic - if bm_enabled: - bm_lib.start_capture_single.argtypes = [c_int, c_int, c_void_p] - bm_lib.read_frame_bgra32_blocking.argtypes = [c_char_p, c_int] - bm_lib.stop_capture_single.argtypes = [] - bm_lib.get_json_length.argtypes = [] - bm_lib.get_json.argtypes = [c_char_p, c_int] - if bm_options is not None: - bm_lib.set_options.argtypes = [c_char_p] - bm_lib.set_options(bm_options.encode()) - self.lib = lib - if bm_enabled: - self.bm_lib = bm_lib - self.cap = lib.create_capture() - self.name_buffer = create_string_buffer(255); - self.buffer = None - self.have_devices = False - self.size = None - self.real_size = None - self.info = None - self.type = None - - def __del__(self): - if self.buffer is not None: - del self.buffer - del self.name_buffer - self.destroy_capture() - - def get_devices(self): - self.have_devices = True - return self.lib.get_devices(self.cap) - - def get_device(self, device_number): - self.lib.get_device(self.cap, device_number, self.name_buffer, 255) - name_str = str(self.name_buffer.value.decode('utf8', 'surrogateescape')) - return name_str - - def get_info(self): - global bm_enabled - # DirectShow - json_length = self.lib.get_json_length(self.cap); - json_buffer = create_string_buffer(json_length) - self.lib.get_json(self.cap, json_buffer, json_length); - json_text = str(json_buffer.value.decode('utf8', 'surrogateescape')) - self.info = json.loads(json_text) - for cam in self.info: - cam["type"] = "DirectShow" - cam["index"] = cam["id"] - - # Blackmagic - if bm_enabled: - json_length = self.bm_lib.get_json_length(); - json_buffer = create_string_buffer(json_length) - self.bm_lib.get_json(json_buffer, json_length); - json_text = str(json_buffer.value.decode('utf8', 'surrogateescape')) - bm_info = json.loads(json_text) - dshow_len = len(self.info) - for cam in bm_info: - cam["type"] = "Blackmagic" - cam["index"] = cam["id"] + dshow_len - self.info.extend(bm_info) - - return self.info - - def capture_device(self, cam, width, height, fps): - if not self.have_devices: - self.get_devices() - ret = self.lib.capture_device(self.cap, cam, width, height, fps) == 1 - if ret: - self.type = "DirectShow" - self.width = self.get_width() - self.height = self.get_height() - self.fps = self.get_fps() - self.flipped = self.get_flipped() - self.colorspace = self.get_colorspace() - self.colorspace_internal = self.get_colorspace_internal() - self.size = self.width * self.height * 4 - self.buffer = create_frame_buffer(self.width, self.height, 4) - else: - self.size = None - self.real_size = None - return ret; - - def capture_device_by_dcap(self, cam, dcap, width, height, fps): - global bm_enabled - if not self.have_devices: - self.get_devices() - if self.info is None: - self.get_info() - fps = int(10000000 / fps) - ret = False - if self.info[cam]['type'] == "DirectShow": - ret = self.lib.capture_device_by_dcap(self.cap, cam, dcap, width, height, fps) == 1 - elif bm_enabled and self.info[cam]['type'] == "Blackmagic": - ret = self.bm_lib.start_capture_single(self.info[cam]['id'], self.info[cam]['caps'][dcap]['bmModecode'], None) == 1 - if ret: - self.type = self.info[cam]['type'] - if self.type == "DirectShow": - self.width = self.get_width() - self.height = self.get_height() - self.fps = self.get_fps() - self.flipped = self.get_flipped() - self.colorspace = self.get_colorspace() - self.colorspace_internal = self.get_colorspace_internal() - self.size = self.width * self.height * 4 * 4 - self.buffer = create_frame_buffer(self.width, self.height, 4) - elif bm_enabled and self.type == "Blackmagic": - self.width = self.info[cam]['caps'][dcap]['minCX'] - self.height = self.info[cam]['caps'][dcap]['minCY'] - self.fps = int(10000000 / self.info[cam]['caps'][dcap]['minInterval']) - self.flipped = True - self.colorspace = 101 - self.colorspace_internal = self.colorspace - self.size = self.width * self.height * 4 - self.buffer = create_frame_buffer(self.width, self.height, 1) - self.real_size = self.size - else: - self.size = None - self.real_size = None - return ret; - - def capture_device_default(self, cam): - if not self.have_devices: - self.get_devices() - ret = self.lib.capture_device_default(self.cap, cam) == 1 - if ret: - self.type = "DirectShow" - self.width = self.get_width() - self.height = self.get_height() - self.fps = self.get_fps() - self.flipped = self.get_flipped() - self.colorspace = self.get_colorspace() - self.colorspace_internal = self.get_colorspace_internal() - self.size = self.width * self.height * 4 * 4 - self.buffer = create_frame_buffer(self.width, self.height, 4) - else: - self.size = None - self.real_size = None - return ret; - - def get_width(self): - return self.lib.get_width(self.cap) - - def get_height(self): - return self.lib.get_height(self.cap) - - def get_fps(self): - return self.lib.get_fps(self.cap) - - def get_flipped(self): - return self.lib.get_flipped(self.cap) != 0 - - def get_colorspace(self): - colorspace = self.lib.get_colorspace(self.cap) - if colorspace == 0: - colorspace = self.lib.get_colorspace_internal(self.cap) - return colorspace - - def get_colorspace_internal(self): - return self.lib.get_colorspace_internal(self.cap) - - def capturing(self): - if self.type == "Blackmagic": - return 1 - return self.lib.capturing(self.cap) == 1 - - def get_frame(self, timeout): - global bm_enabled - if self.size is None: - return None - if self.type == "DirectShow": - self.real_size = self.lib.get_frame(self.cap, timeout, self.buffer, self.size) - elif bm_enabled and self.type == "Blackmagic": - self.bm_lib.read_frame_bgra32_blocking(self.buffer, self.size) - else: - return None - img = np.frombuffer(self.buffer, dtype=np.uint8)[0:self.real_size] - if self.colorspace in [100, 101]: - if self.real_size == self.height * self.width * 4: - img = cv2.cvtColor(img.reshape((self.height,self.width,4)), cv2.COLOR_BGRA2BGR) - elif self.real_size == self.height * self.width * 3: - img = img.reshape((self.height,self.width,3)) - else: - return None - if not self.flipped: - img = cv2.flip(img, 0) - return img - elif self.colorspace == 200 and self.real_size == (3 * self.height // 2) * self.width: - img = cv2.cvtColor(img.reshape((3 * self.height // 2,self.width,1)), cv2.COLOR_YUV2BGR_I420) - elif self.colorspace == 201 and self.real_size == (3 * self.height // 2) * self.width: - img = cv2.cvtColor(img.reshape((3 * self.height // 2,self.width,1)), cv2.COLOR_YUV2BGR_NV12) - elif self.colorspace == 202 and self.real_size == (3 * self.height // 2) * self.width: - img = cv2.cvtColor(img.reshape((3 * self.height // 2,self.width,1)), cv2.COLOR_YUV2BGR_YV12) - elif self.colorspace == 203 and self.real_size == self.height * self.width: - img = cv2.cvtColor(img.reshape((self.height,self.width,1)), cv2.COLOR_GRAY2BGR) - elif self.colorspace == 300 and self.real_size == self.height * self.width * 2: - img = cv2.cvtColor(img.reshape((self.height,self.width,2)), cv2.COLOR_YUV2BGR_YVYU) - elif self.colorspace == 301 and self.real_size == self.height * self.width * 2: - img = cv2.cvtColor(img.reshape((self.height,self.width,2)), cv2.COLOR_YUV2BGR_YUY2) - elif self.colorspace == 302 and self.real_size == self.height * self.width * 2: - img = cv2.cvtColor(img.reshape((self.height,self.width,2)), cv2.COLOR_YUV2BGR_UYVY) - elif self.colorspace == 303: - return None - elif self.colorspace == 400 and self.real_size > 4: - img = cv2.imdecode(img, cv2.IMREAD_COLOR); - else: - return None - if self.flipped: - img = cv2.flip(img, 0) - return img - - def stop_capture(self): - global bm_enabled - self.size = None - self.real_size = None - if self.type == "DirectShow": - return self.lib.stop_capture(self.cap) - elif bm_enabled and self.type == "Blackmagic": - return self.bm_lib.stop_capture_single() != 0 - return True - - def destroy_capture(self): - if self.cap is None: - return 0 - self.stop_capture() - ret = self.lib.destroy_capture(self.cap) - self.cap = None - self.size = None - self.real_size = None - return ret - -if __name__ == "__main__": - cam = 0 - width = 1280 - height = 720 - fps = 30 - if len(sys.argv) > 1: - cam = int(sys.argv[1]) - if len(sys.argv) > 2: - width = int(sys.argv[2]) - if len(sys.argv) > 3: - height = int(sys.argv[3]) - if len(sys.argv) > 4: - fps = int(sys.argv[4]) - - cap = DShowCapture() - devices = cap.get_devices() - print("Devices: ", devices) - for i in range(devices): - print(f"{i} {cap.get_device(i)}") - - print(f"Capturing: {cap.capture_device(cam, width, height, fps)}") - width = cap.get_width() - height = cap.get_height() - flipped = cap.get_flipped() - print(f"Width: {width} Height: {height} FPS: {cap.get_fps()} Flipped: {flipped} Colorspace: {cap.get_colorspace()} Internal: {cap.get_colorspace_internal()}") - - while True: - img = cap.get_frame(1000) - if img is not None: - cv2.imshow("DShowCapture", img) - if cv2.waitKey(1) & 0xFF == ord('q'): - sys.exit(0) - else: - print("Lost frame") - - cap.stop_capture() - cap.destroy_capture() - del cap \ No newline at end of file diff --git a/dshowcapture/dshowcapture_x64.dll b/dshowcapture/dshowcapture_x64.dll deleted file mode 100644 index e7f30fd..0000000 Binary files a/dshowcapture/dshowcapture_x64.dll and /dev/null differ diff --git a/dshowcapture/dshowcapture_x86.dll b/dshowcapture/dshowcapture_x86.dll deleted file mode 100644 index 9eb7308..0000000 Binary files a/dshowcapture/dshowcapture_x86.dll and /dev/null differ diff --git a/dshowcapture/libminibmcapture32.dll b/dshowcapture/libminibmcapture32.dll deleted file mode 100644 index 156b184..0000000 Binary files a/dshowcapture/libminibmcapture32.dll and /dev/null differ diff --git a/dshowcapture/libminibmcapture64.dll b/dshowcapture/libminibmcapture64.dll deleted file mode 100644 index a9139ba..0000000 Binary files a/dshowcapture/libminibmcapture64.dll and /dev/null differ diff --git a/facetracker.py b/facetracker.py index 205b2fb..32226d3 100644 --- a/facetracker.py +++ b/facetracker.py @@ -2,30 +2,21 @@ import copy import os import sys import argparse -import traceback -import gc parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("-i", "--ip", help="Set IP address for sending tracking data", default="127.0.0.1") parser.add_argument("-p", "--port", type=int, help="Set port for sending tracking data", default=11573) if os.name == 'nt': - parser.add_argument("-l", "--list-cameras", type=int, help="Set this to 1 to list the available cameras and quit, set this to 2 or higher to output only the names", default=0) - parser.add_argument("-a", "--list-dcaps", type=int, help="Set this to -1 to list all cameras and their available capabilities, set this to a camera id to list that camera's capabilities", default=None) + parser.add_argument("-l", "--list-cameras", type=int, help="Set this to 1 to list the available cameras and quit, set this to a number higher than 1 to output only the names", default=0) parser.add_argument("-W", "--width", type=int, help="Set camera and raw RGB width", default=640) parser.add_argument("-H", "--height", type=int, help="Set camera and raw RGB height", default=360) - parser.add_argument("-D", "--dcap", type=int, help="Set which device capability line to use or -1 to use the default camera settings (FPS still need to be set separately)", default=None) - parser.add_argument("-B", "--blackmagic", type=int, help="When set to 1, special support for Blackmagic devices is enabled", default=0) + parser.add_argument("-F", "--fps", type=int, help="Set camera frames per second", default=24) else: parser.add_argument("-W", "--width", type=int, help="Set raw RGB width", default=640) parser.add_argument("-H", "--height", type=int, help="Set raw RGB height", default=360) -if sys.platform == 'linux': - parser.add_argument("--dformat", type=str, help="Set which device format to use (MJPG, YUYV, RGB3, ...)", default=None) -parser.add_argument("-F", "--fps", type=int, help="Set camera frames per second", default=24) parser.add_argument("-c", "--capture", help="Set camera ID (0, 1...) or video file", default="0") -parser.add_argument("-M", "--mirror-input", action="store_true", help="Process a mirror image of the input video") parser.add_argument("-m", "--max-threads", type=int, help="Set the maximum number of threads", default=1) -parser.add_argument("-t", "--threshold", type=float, help="Set minimum confidence threshold for face tracking", default=None) -parser.add_argument("-d", "--detection-threshold", type=float, help="Set minimum confidence threshold for face detection", default=0.6) +parser.add_argument("-t", "--threshold", type=float, help="Set minimum confidence threshold for face detection", default=0.65) parser.add_argument("-v", "--visualize", type=int, help="Set this to 1 to visualize the tracking, to 2 to also show face ids, to 3 to add confidence values or to 4 to add numbers to the point display", default=0) parser.add_argument("-P", "--pnp-points", type=int, help="Set this to 1 to add the 3D fitting points to the visualization", default=0) parser.add_argument("-s", "--silent", type=int, help="Set this to 1 to prevent text output on the console", default=0) @@ -33,95 +24,31 @@ parser.add_argument("--faces", type=int, help="Set the maximum number of faces ( parser.add_argument("--scan-retinaface", type=int, help="When set to 1, scanning for additional faces will be performed using RetinaFace in a background thread, otherwise a simpler, faster face detection mechanism is used. When the maximum number of faces is 1, this option does nothing.", default=0) parser.add_argument("--scan-every", type=int, help="Set after how many frames a scan for new faces should run", default=3) parser.add_argument("--discard-after", type=int, help="Set the how long the tracker should keep looking for lost faces", default=10) -parser.add_argument("--max-feature-updates", type=int, help="This is the number of seconds after which feature min/max/medium values will no longer be updated once a face has been detected.", default=900) -parser.add_argument("--no-3d-adapt", type=int, help="When set to 1, the 3D face model will not be adapted to increase the fit", default=1) -parser.add_argument("--try-hard", type=int, help="When set to 1, the tracker will try harder to find a face", default=0) parser.add_argument("--video-out", help="Set this to the filename of an AVI file to save the tracking visualization as a video", default=None) -parser.add_argument("--video-scale", type=int, help="This is a resolution scale factor applied to the saved AVI file", default=1, choices=[1,2,3,4]) -parser.add_argument("--video-fps", type=float, help="This sets the frame rate of the output AVI file", default=24) parser.add_argument("--raw-rgb", type=int, help="When this is set, raw RGB frames of the size given with \"-W\" and \"-H\" are read from standard input instead of reading a video", default=0) parser.add_argument("--log-data", help="You can set a filename to which tracking data will be logged here", default="") -parser.add_argument("--log-output", help="You can set a filename to console output will be logged here", default="") -parser.add_argument("--model", type=int, help="This can be used to select the tracking model. Higher numbers are models with better tracking quality, but slower speed, except for model 4, which is wink optimized. Models 1 and 0 tend to be too rigid for expression and blink detection. Model -2 is roughly equivalent to model 1, but faster. Model -3 is between models 0 and -1.", default=3, choices=[-3, -2, -1, 0, 1, 2, 3, 4]) +parser.add_argument("--model", type=int, help="This can be used to select the tracking model. Higher numbers are models with better tracking quality, but slower speed. Models 1 and 0 tend to be too rigid for expression and blink detection.", default=3, choices=[0, 1, 2, 3]) parser.add_argument("--model-dir", help="This can be used to specify the path to the directory containing the .onnx model files", default=None) -parser.add_argument("--gaze-tracking", type=int, help="When set to 1, gaze tracking is enabled, which makes things slightly slower", default=1) +parser.add_argument("--gaze-tracking", type=int, help="When set to 1, experimental blink detection and gaze tracking are enabled, which makes things slightly slower", default=1) parser.add_argument("--face-id-offset", type=int, help="When set, this offset is added to all face ids, which can be useful for mixing tracking data from multiple network sources", default=0) parser.add_argument("--repeat-video", type=int, help="When set to 1 and a video file was specified with -c, the tracker will loop the video until interrupted", default=0) parser.add_argument("--dump-points", type=str, help="When set to a filename, the current face 3D points are made symmetric and dumped to the given file when quitting the visualization with the \"q\" key", default="") -parser.add_argument("--benchmark", type=int, help="When set to 1, the different tracking models are benchmarked, starting with the best and ending with the fastest and with gaze tracking disabled for models with negative IDs", default=0) -if os.name == 'nt': - parser.add_argument("--use-dshowcapture", type=int, help="When set to 1, libdshowcapture will be used for video input instead of OpenCV", default=1) - parser.add_argument("--blackmagic-options", type=str, help="When set, this additional option string is passed to the blackmagic capture library", default=None) - parser.add_argument("--priority", type=int, help="When set, the process priority will be changed", default=None, choices=[0, 1, 2, 3, 4, 5]) args = parser.parse_args() -os.environ["OMP_NUM_THREADS"] = str(args.max_threads) +os.environ["OMP_NUM_THREADS"] = "1" -class OutputLog(object): - def __init__(self, fh, output): - self.fh = fh - self.output = output - def write(self, buf): - if self.fh is not None: - self.fh.write(buf) - self.output.write(buf) - self.flush() - def flush(self): - if self.fh is not None: - self.fh.flush() - self.output.flush() -output_logfile = None -if args.log_output != "": - output_logfile = open(args.log_output, "w") -sys.stdout = OutputLog(output_logfile, sys.stdout) -sys.stderr = OutputLog(output_logfile, sys.stderr) - -if os.name == 'nt': - import dshowcapture - if args.blackmagic == 1: - dshowcapture.set_bm_enabled(True) - if args.blackmagic_options is not None: - dshowcapture.set_options(args.blackmagic_options) - if args.priority is not None: - import psutil - classes = [psutil.IDLE_PRIORITY_CLASS, psutil.BELOW_NORMAL_PRIORITY_CLASS, psutil.NORMAL_PRIORITY_CLASS, psutil.ABOVE_NORMAL_PRIORITY_CLASS, psutil.HIGH_PRIORITY_CLASS, psutil.REALTIME_PRIORITY_CLASS] - p = psutil.Process(os.getpid()) - p.nice(classes[args.priority]) - -if os.name == 'nt' and (args.list_cameras > 0 or args.list_dcaps is not None): - cap = dshowcapture.DShowCapture() - info = cap.get_info() - unit = 10000000.; - if args.list_dcaps is not None: - formats = {0: "Any", 1: "Unknown", 100: "ARGB", 101: "XRGB", 200: "I420", 201: "NV12", 202: "YV12", 203: "Y800", 300: "YVYU", 301: "YUY2", 302: "UYVY", 303: "HDYC (Unsupported)", 400: "MJPEG", 401: "H264" } - for cam in info: - if args.list_dcaps == -1: - type = "" - if cam['type'] == "Blackmagic": - type = "Blackmagic: " - print(f"{cam['index']}: {type}{cam['name']}") - if args.list_dcaps != -1 and args.list_dcaps != cam['index']: - continue - for caps in cam['caps']: - format = caps['format'] - if caps['format'] in formats: - format = formats[caps['format']] - if caps['minCX'] == caps['maxCX'] and caps['minCY'] == caps['maxCY']: - print(f" {caps['id']}: Resolution: {caps['minCX']}x{caps['minCY']} FPS: {unit/caps['maxInterval']:.3f}-{unit/caps['minInterval']:.3f} Format: {format}") - else: - print(f" {caps['id']}: Resolution: {caps['minCX']}x{caps['minCY']}-{caps['maxCX']}x{caps['maxCY']} FPS: {unit/caps['maxInterval']:.3f}-{unit/caps['minInterval']:.3f} Format: {format}") - else: +if os.name == 'nt' and args.list_cameras > 0: + import escapi + escapi.init() + camera_count = escapi.count_capture_devices() + if args.list_cameras == 1: + print("Available cameras:") + for i in range(camera_count): + camera_name = escapi.device_name(i).decode() if args.list_cameras == 1: - print("Available cameras:") - for cam in info: - type = "" - if cam['type'] == "Blackmagic": - type = "Blackmagic: " - if args.list_cameras == 1: - print(f"{cam['index']}: {type}{cam['name']}") - else: - print(f"{type}{cam['name']}") - cap.destroy_capture() + print(f"{i}: {camera_name}") + else: + print(camera_name) sys.exit(0) import numpy as np @@ -129,25 +56,8 @@ import time import cv2 import socket import struct -import json -from input_reader import InputReader, VideoReader, DShowCaptureReader, try_int -from tracker import Tracker, get_model_base_path - -if args.benchmark > 0: - model_base_path = get_model_base_path(args.model_dir) - im = cv2.imread(os.path.join(model_base_path, "benchmark.bin"), cv2.IMREAD_COLOR) - results = [] - for model_type in [3, 2, 1, 0, -1, -2, -3]: - tracker = Tracker(224, 224, threshold=0.1, max_threads=args.max_threads, max_faces=1, discard_after=0, scan_every=0, silent=True, model_type=model_type, model_dir=args.model_dir, no_gaze=(model_type == -1), detection_threshold=0.1, use_retinaface=0, max_feature_updates=900, static_model=True if args.no_3d_adapt == 1 else False) - tracker.detected = 1 - tracker.faces = [(0, 0, 224, 224)] - total = 0.0 - for i in range(100): - start = time.perf_counter() - r = tracker.predict(im) - total += time.perf_counter() - start - print(1. / (total / 100.)) - sys.exit(0) +from input_reader import InputReader, VideoReader, list_cameras +from tracker import Tracker target_ip = args.ip target_port = args.port @@ -155,19 +65,10 @@ target_port = args.port if args.faces >= 40: print("Transmission of tracking data over network is not supported with 40 or more faces.") -fps = args.fps -dcap = None -use_dshowcapture_flag = False +fps = 0 if os.name == 'nt': - dcap = args.dcap - use_dshowcapture_flag = True if args.use_dshowcapture == 1 else False - input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps, use_dshowcapture=use_dshowcapture_flag, dcap=dcap) - if args.dcap == -1 and type(input_reader) == DShowCaptureReader: - fps = min(fps, input_reader.device.get_fps()) -elif sys.platform == 'linux' and args.dformat: - input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps, dcap=args.dformat) -else: - input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps) + fps = args.fps +input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps) if type(input_reader.reader) == VideoReader: fps = 0 @@ -178,7 +79,6 @@ height = 0 width = 0 tracker = None sock = None -total_tracking_time = 0.0 tracking_time = 0.0 tracking_frames = 0 frame_count = 0 @@ -188,61 +88,40 @@ features = ["eye_l", "eye_r", "eyebrow_steepness_l", "eyebrow_updown_l", "eyebro if args.log_data != "": log = open(args.log_data, "w") log.write("Frame,Time,Width,Height,FPS,Face,FaceID,RightOpen,LeftOpen,AverageConfidence,Success3D,PnPError,RotationQuat.X,RotationQuat.Y,RotationQuat.Z,RotationQuat.W,Euler.X,Euler.Y,Euler.Z,RVec.X,RVec.Y,RVec.Z,TVec.X,TVec.Y,TVec.Z") - for i in range(68): + for i in range(66): log.write(f",Landmark[{i}].X,Landmark[{i}].Y,Landmark[{i}].Confidence") - for i in range(70): + for i in range(66): log.write(f",Point3D[{i}].X,Point3D[{i}].Y,Point3D[{i}].Z") for feature in features: log.write(f",{feature}") log.write("\r\n") log.flush() -is_camera = args.capture == str(try_int(args.capture)) - try: - attempt = 0 frame_time = time.perf_counter() target_duration = 0 if fps > 0: target_duration = 1. / float(fps) repeat = args.repeat_video != 0 and type(input_reader.reader) == VideoReader need_reinit = 0 - failures = 0 - source_name = input_reader.name while repeat or input_reader.is_open(): if not input_reader.is_open() or need_reinit == 1: - input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps, use_dshowcapture=use_dshowcapture_flag, dcap=dcap) - if input_reader.name != source_name: - print(f"Failed to reinitialize camera and got {input_reader.name} instead of {source_name}.") - sys.exit(1) + input_reader = InputReader(args.capture, args.raw_rgb, args.width, args.height, fps) need_reinit = 2 - time.sleep(0.02) + time.sleep(0.001) continue if not input_reader.is_ready(): - time.sleep(0.02) + time.sleep(0.001) continue ret, frame = input_reader.read() - if ret and args.mirror_input: - frame = cv2.flip(frame, 1) if not ret: if repeat: if need_reinit == 0: need_reinit = 1 continue - elif is_camera: - attempt += 1 - if attempt > 30: - break - else: - time.sleep(0.02) - if attempt == 3: - need_reinit = 1 - continue - else: - break; + break - attempt = 0 need_reinit = 0 frame_count += 1 now = time.time() @@ -251,197 +130,179 @@ try: first = False height, width, channels = frame.shape sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - tracker = Tracker(width, height, threshold=args.threshold, max_threads=args.max_threads, max_faces=args.faces, discard_after=args.discard_after, scan_every=args.scan_every, silent=False if args.silent == 0 else True, model_type=args.model, model_dir=args.model_dir, no_gaze=False if args.gaze_tracking != 0 and args.model != -1 else True, detection_threshold=args.detection_threshold, use_retinaface=args.scan_retinaface, max_feature_updates=args.max_feature_updates, static_model=True if args.no_3d_adapt == 1 else False, try_hard=args.try_hard == 1) - if args.video_out is not None: - out = cv2.VideoWriter(args.video_out, cv2.VideoWriter_fourcc('F','F','V','1'), args.video_fps, (width * args.video_scale, height * args.video_scale)) + tracker = Tracker(width, height, threshold=args.threshold, max_threads=args.max_threads, max_faces=args.faces, discard_after=args.discard_after, scan_every=args.scan_every, silent=False if args.silent == 0 else True, model_type=args.model, model_dir=args.model_dir, no_gaze=False if args.gaze_tracking != 0 else True, use_retinaface=args.scan_retinaface) + if not args.video_out is None: + out = cv2.VideoWriter(args.video_out, cv2.VideoWriter_fourcc('F','F','V','1'), 24, (width,height)) - try: - inference_start = time.perf_counter() - faces = tracker.predict(frame) - if len(faces) > 0: - inference_time = (time.perf_counter() - inference_start) - total_tracking_time += inference_time - tracking_time += inference_time / len(faces) - tracking_frames += 1 - packet = bytearray() - detected = False - for face_num, f in enumerate(faces): - f = copy.copy(f) - f.id += args.face_id_offset - if f.eye_blink is None: - f.eye_blink = [1, 1] - right_state = "O" if f.eye_blink[0] > 0.30 else "-" - left_state = "O" if f.eye_blink[1] > 0.30 else "-" - if args.silent == 0: - print(f"Confidence[{f.id}]: {f.conf:.4f} / 3D fitting error: {f.pnp_error:.4f} / Eyes: {left_state}, {right_state}") - detected = True - if not f.success: - pts_3d = np.zeros((70, 3), np.float32) - packet.extend(bytearray(struct.pack("d", now))) - packet.extend(bytearray(struct.pack("i", f.id))) - packet.extend(bytearray(struct.pack("f", width))) - packet.extend(bytearray(struct.pack("f", height))) - packet.extend(bytearray(struct.pack("f", f.eye_blink[0]))) - packet.extend(bytearray(struct.pack("f", f.eye_blink[1]))) - packet.extend(bytearray(struct.pack("B", 1 if f.success else 0))) - packet.extend(bytearray(struct.pack("f", f.pnp_error))) - packet.extend(bytearray(struct.pack("f", f.quaternion[0]))) - packet.extend(bytearray(struct.pack("f", f.quaternion[1]))) - packet.extend(bytearray(struct.pack("f", f.quaternion[2]))) - packet.extend(bytearray(struct.pack("f", f.quaternion[3]))) - packet.extend(bytearray(struct.pack("f", f.euler[0]))) - packet.extend(bytearray(struct.pack("f", f.euler[1]))) - packet.extend(bytearray(struct.pack("f", f.euler[2]))) - packet.extend(bytearray(struct.pack("f", f.translation[0]))) - packet.extend(bytearray(struct.pack("f", f.translation[1]))) - packet.extend(bytearray(struct.pack("f", f.translation[2]))) - if log is not None: - log.write(f"{frame_count},{now},{width},{height},{fps},{face_num},{f.id},{f.eye_blink[0]},{f.eye_blink[1]},{f.conf},{f.success},{f.pnp_error},{f.quaternion[0]},{f.quaternion[1]},{f.quaternion[2]},{f.quaternion[3]},{f.euler[0]},{f.euler[1]},{f.euler[2]},{f.rotation[0]},{f.rotation[1]},{f.rotation[2]},{f.translation[0]},{f.translation[1]},{f.translation[2]}") - for (x,y,c) in f.lms: - packet.extend(bytearray(struct.pack("f", c))) - if args.visualize > 1: - frame = cv2.putText(frame, str(f.id), (int(f.bbox[0]), int(f.bbox[1])), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255,0,255)) - if args.visualize > 2: - frame = cv2.putText(frame, f"{f.conf:.4f}", (int(f.bbox[0] + 18), int(f.bbox[1] - 6)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255)) - for pt_num, (x,y,c) in enumerate(f.lms): - packet.extend(bytearray(struct.pack("f", y))) - packet.extend(bytearray(struct.pack("f", x))) - if log is not None: - log.write(f",{y},{x},{c}") - if pt_num == 66 and (f.eye_blink[0] < 0.30 or c < 0.20): - continue - if pt_num == 67 and (f.eye_blink[1] < 0.30 or c < 0.20): - continue + inference_start = time.perf_counter() + faces = tracker.predict(frame) + if len(faces) > 0: + tracking_time += (time.perf_counter() - inference_start) / len(faces) + tracking_frames += 1 + packet = bytearray() + detected = False + for face_num, f in enumerate(faces): + f = copy.copy(f) + f.id += args.face_id_offset + if f.eye_blink is None: + f.eye_blink = [1, 1] + right_state = "O" if f.eye_blink[0] > 0.30 else "-" + left_state = "O" if f.eye_blink[1] > 0.30 else "-" + if args.silent == 0: + print(f"Confidence[{f.id}]: {f.conf:.4f} / 3D fitting error: {f.pnp_error:.4f} / Eyes: {left_state}, {right_state}") + detected = True + if not f.success: + pts_3d = np.zeros((70, 3), np.float32) + packet.extend(bytearray(struct.pack("d", now))) + packet.extend(bytearray(struct.pack("i", f.id))) + packet.extend(bytearray(struct.pack("f", width))) + packet.extend(bytearray(struct.pack("f", height))) + packet.extend(bytearray(struct.pack("f", f.eye_blink[0]))) + packet.extend(bytearray(struct.pack("f", f.eye_blink[1]))) + packet.extend(bytearray(struct.pack("B", 1 if f.success else 0))) + packet.extend(bytearray(struct.pack("f", f.pnp_error))) + packet.extend(bytearray(struct.pack("f", f.quaternion[0]))) + packet.extend(bytearray(struct.pack("f", f.quaternion[1]))) + packet.extend(bytearray(struct.pack("f", f.quaternion[2]))) + packet.extend(bytearray(struct.pack("f", f.quaternion[3]))) + packet.extend(bytearray(struct.pack("f", f.euler[0]))) + packet.extend(bytearray(struct.pack("f", f.euler[1]))) + packet.extend(bytearray(struct.pack("f", f.euler[2]))) + packet.extend(bytearray(struct.pack("f", f.translation[0]))) + packet.extend(bytearray(struct.pack("f", f.translation[1]))) + packet.extend(bytearray(struct.pack("f", f.translation[2]))) + if not log is None: + log.write(f"{frame_count},{now},{width},{height},{args.fps},{face_num},{f.id},{f.eye_blink[0]},{f.eye_blink[1]},{f.conf},{f.success},{f.pnp_error},{f.quaternion[0]},{f.quaternion[1]},{f.quaternion[2]},{f.quaternion[3]},{f.euler[0]},{f.euler[1]},{f.euler[2]},{f.rotation[0]},{f.rotation[1]},{f.rotation[2]},{f.translation[0]},{f.translation[1]},{f.translation[2]}") + for (x,y,c) in f.lms: + packet.extend(bytearray(struct.pack("f", c))) + if args.visualize > 1: + frame = cv2.putText(frame, str(f.id), (int(f.bbox[0]), int(f.bbox[1])), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255,0,255)) + if args.visualize > 2: + frame = cv2.putText(frame, f"{f.conf:.4f}", (int(f.bbox[0] + 18), int(f.bbox[1] - 6)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0)) + for pt_num, (x,y,c) in enumerate(f.lms): + packet.extend(bytearray(struct.pack("f", y))) + packet.extend(bytearray(struct.pack("f", x))) + if not log is None: + log.write(f",{y},{x},{c}") + if pt_num == 66 and f.eye_blink[0] < 0.30: + continue + if pt_num == 67 and f.eye_blink[1] < 0.30: + continue + x = int(x + 0.5) + y = int(y + 0.5) + if args.visualize != 0 or not out is None: + if args.visualize > 3: + frame = cv2.putText(frame, str(pt_num), (int(y), int(x)), cv2.FONT_HERSHEY_SIMPLEX, 0.25, (255,255,0)) + color = (0, 0, 255) + if pt_num >= 66: + color = (255, 255, 0) + if not (x < 0 or y < 0 or x >= height or y >= width): + frame[int(x), int(y)] = color + x += 1 + if not (x < 0 or y < 0 or x >= height or y >= width): + frame[int(x), int(y)] = color + y += 1 + if not (x < 0 or y < 0 or x >= height or y >= width): + frame[int(x), int(y)] = color + x -= 1 + if not (x < 0 or y < 0 or x >= height or y >= width): + frame[int(x), int(y)] = color + if args.pnp_points != 0 and (args.visualize != 0 or not out is None) and f.rotation is not None: + if args.pnp_points > 1: + projected = cv2.projectPoints(f.face_3d[0:66], f.rotation, f.translation, tracker.camera, tracker.dist_coeffs) + else: + projected = cv2.projectPoints(f.contour, f.rotation, f.translation, tracker.camera, tracker.dist_coeffs) + for [(x,y)] in projected[0]: x = int(x + 0.5) y = int(y + 0.5) - if args.visualize != 0 or out is not None: - if args.visualize > 3: - frame = cv2.putText(frame, str(pt_num), (int(y), int(x)), cv2.FONT_HERSHEY_SIMPLEX, 0.25, (255,255,0)) - color = (0, 255, 0) - if pt_num >= 66: - color = (255, 255, 0) - if not (x < 0 or y < 0 or x >= height or y >= width): - cv2.circle(frame, (y, x), 1, color, -1) - if args.pnp_points != 0 and (args.visualize != 0 or out is not None) and f.rotation is not None: - if args.pnp_points > 1: - projected = cv2.projectPoints(f.face_3d[0:66], f.rotation, f.translation, tracker.camera, tracker.dist_coeffs) - else: - projected = cv2.projectPoints(f.contour, f.rotation, f.translation, tracker.camera, tracker.dist_coeffs) - for [(x,y)] in projected[0]: - x = int(x + 0.5) - y = int(y + 0.5) - if not (x < 0 or y < 0 or x >= height or y >= width): - frame[int(x), int(y)] = (0, 255, 255) - x += 1 - if not (x < 0 or y < 0 or x >= height or y >= width): - frame[int(x), int(y)] = (0, 255, 255) - y += 1 - if not (x < 0 or y < 0 or x >= height or y >= width): - frame[int(x), int(y)] = (0, 255, 255) - x -= 1 - if not (x < 0 or y < 0 or x >= height or y >= width): - frame[int(x), int(y)] = (0, 255, 255) - for (x,y,z) in f.pts_3d: - packet.extend(bytearray(struct.pack("f", x))) - packet.extend(bytearray(struct.pack("f", -y))) - packet.extend(bytearray(struct.pack("f", -z))) - if log is not None: - log.write(f",{x},{-y},{-z}") - if f.current_features is None: - f.current_features = {} - for feature in features: - if not feature in f.current_features: - f.current_features[feature] = 0 - packet.extend(bytearray(struct.pack("f", f.current_features[feature]))) - if log is not None: - log.write(f",{f.current_features[feature]}") - if log is not None: - log.write("\r\n") - log.flush() + if not (x < 0 or y < 0 or x >= height or y >= width): + frame[int(x), int(y)] = (0, 255, 255) + x += 1 + if not (x < 0 or y < 0 or x >= height or y >= width): + frame[int(x), int(y)] = (0, 255, 255) + y += 1 + if not (x < 0 or y < 0 or x >= height or y >= width): + frame[int(x), int(y)] = (0, 255, 255) + x -= 1 + if not (x < 0 or y < 0 or x >= height or y >= width): + frame[int(x), int(y)] = (0, 255, 255) + for (x,y,z) in f.pts_3d: + packet.extend(bytearray(struct.pack("f", x))) + packet.extend(bytearray(struct.pack("f", -y))) + packet.extend(bytearray(struct.pack("f", -z))) + if not log is None: + log.write(f",{x},{-y},{-z}") + if f.current_features is None: + f.current_features = {} + for feature in features: + if not feature in f.current_features: + f.current_features[feature] = 0 + packet.extend(bytearray(struct.pack("f", f.current_features[feature]))) + if not log is None: + log.write(f",{f.current_features[feature]}") + if not log is None: + log.write("\r\n") + log.flush() - if detected and len(faces) < 40: - sock.sendto(packet, (target_ip, target_port)) + if detected and len(faces) < 40: + sock.sendto(packet, (target_ip, target_port)) - if out is not None: - video_frame = frame - if args.video_scale != 1: - video_frame = cv2.resize(frame, (width * args.video_scale, height * args.video_scale), interpolation=cv2.INTER_NEAREST) - out.write(video_frame) - if args.video_scale != 1: - del video_frame + if not out is None: + out.write(frame) - if args.visualize != 0: - cv2.imshow('OpenSeeFace Visualization', frame) - if cv2.waitKey(1) & 0xFF == ord('q'): - if args.dump_points != "" and faces is not None and len(faces) > 0: - np.set_printoptions(threshold=sys.maxsize, precision=15) - pairs = [ - (0, 16), - (1, 15), - (2, 14), - (3, 13), - (4, 12), - (5, 11), - (6, 10), - (7, 9), - (17, 26), - (18, 25), - (19, 24), - (20, 23), - (21, 22), - (31, 35), - (32, 34), - (36, 45), - (37, 44), - (38, 43), - (39, 42), - (40, 47), - (41, 46), - (48, 52), - (49, 51), - (56, 54), - (57, 53), - (58, 62), - (59, 61), - (65, 63) - ] - points = copy.copy(faces[0].face_3d) - for a, b in pairs: - x = (points[a, 0] - points[b, 0]) / 2.0 - y = (points[a, 1] + points[b, 1]) / 2.0 - z = (points[a, 2] + points[b, 2]) / 2.0 - points[a, 0] = x - points[b, 0] = -x - points[[a, b], 1] = y - points[[a, b], 2] = z - points[[8, 27, 28, 29, 33, 50, 55, 60, 64], 0] = 0.0 - points[30, :] = 0.0 - with open(args.dump_points, "w") as fh: - fh.write(repr(points)) - break - failures = 0 - except Exception as e: - if e.__class__ == KeyboardInterrupt: - if args.silent == 0: - print("Quitting") + if args.visualize != 0: + cv2.imshow('OpenSeeFace Visualization', frame) + if cv2.waitKey(1) & 0xFF == ord('q'): + if args.dump_points != "" and not faces is None and len(faces) > 0: + np.set_printoptions(threshold=sys.maxsize, precision=15) + pairs = [ + (0, 16), + (1, 15), + (2, 14), + (3, 13), + (4, 12), + (5, 11), + (6, 10), + (7, 9), + (17, 26), + (18, 25), + (19, 24), + (20, 23), + (21, 22), + (31, 35), + (32, 34), + (36, 45), + (37, 44), + (38, 43), + (39, 42), + (40, 47), + (41, 46), + (48, 52), + (49, 51), + (56, 54), + (57, 53), + (58, 62), + (59, 61), + (65, 63) + ] + points = copy.copy(faces[0].face_3d) + for a, b in pairs: + x = (points[a, 0] - points[b, 0]) / 2.0 + y = (points[a, 1] + points[b, 1]) / 2.0 + z = (points[a, 2] + points[b, 2]) / 2.0 + points[a, 0] = x + points[b, 0] = -x + points[[a, b], 1] = y + points[[a, b], 2] = z + points[[8, 27, 28, 29, 33, 50, 55, 60, 64], 0] = 0.0 + points[30, :] = 0.0 + with open(args.dump_points, "w") as fh: + fh.write(repr(points)) break - traceback.print_exc() - failures += 1 - if failures > 30: - break - - collected = False - del frame duration = time.perf_counter() - frame_time while duration < target_duration: - if not collected: - gc.collect() - collected = True - duration = time.perf_counter() - frame_time - sleep_time = target_duration - duration - if sleep_time > 0: - time.sleep(sleep_time) + time.sleep(target_duration - duration) duration = time.perf_counter() - frame_time frame_time = time.perf_counter() except KeyboardInterrupt: @@ -449,12 +310,10 @@ except KeyboardInterrupt: print("Quitting") input_reader.close() -if out is not None: +if not out is None: out.release() -if args.visualize != 0: - cv2.destroyAllWindows() +cv2.destroyAllWindows() if args.silent == 0 and tracking_frames > 0: - average_tracking_time = 1000 * tracking_time / tracking_frames - print(f"Average tracking time per detected face: {average_tracking_time:.2f} ms") - print(f"Tracking time: {total_tracking_time:.3f} s\nFrames: {tracking_frames}") + tracking_time = 1000 * tracking_time / tracking_frames + print(f"Average tracking time per detected face: {tracking_time:.2f} ms") diff --git a/facetracker.spec b/facetracker.spec deleted file mode 100644 index 060d850..0000000 --- a/facetracker.spec +++ /dev/null @@ -1,53 +0,0 @@ -# -*- mode: python ; coding: utf-8 -*- - -block_cipher = None - - -a = Analysis(['facetracker.py'], - pathex=['C:\\OpenSeeFaceBuild'], - binaries=[('dshowcapture/dshowcapture_x86.dll', '.'), ('dshowcapture/dshowcapture_x64.dll', '.'), ('dshowcapture/libminibmcapture32.dll', '.'), ('dshowcapture/libminibmcapture64.dll', '.'), ('escapi/escapi_x86.dll', '.'), ('escapi/escapi_x64.dll', '.'), ('run.bat', '.'), ('msvcp140.dll', '.'), ('vcomp140.dll', '.'), ('concrt140.dll', '.'), ('vccorlib140.dll', '.')], - datas=[], - hiddenimports=[], - hookspath=[], - runtime_hooks=[], - excludes=['matplotlib', 'mpl-data', 'PyInstaller', 'pywt', 'skimage', 'scipy', 'pyinstaller'], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher, - noarchive=False) - -remove_bin = [] -for bin in a.binaries: - if bin[0].startswith("opencv_video") or bin[0].startswith("PyInstaller"): - remove_bin.append(bin[0]) - print(bin) -remove_dat = [] -for bin in a.datas: - if bin[0].startswith("opencv_video") or bin[0].startswith("PyInstaller"): - remove_dat.append(bin[0]) - print("data ", bin) - -a.binaries = [x for x in a.binaries if not x[0] in remove_bin] -a.datas = [x for x in a.datas if not x[0] in remove_dat] - -pyz = PYZ(a.pure, a.zipped_data, - cipher=block_cipher) -exe = EXE(pyz, - a.scripts, - [], - exclude_binaries=True, - name='facetracker', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - console=True ) - -coll = COLLECT(exe, - a.binaries, - a.zipfiles, - a.datas, - strip=False, - upx=True, - upx_exclude=[], - name='facetracker') diff --git a/input_reader.py b/input_reader.py index 2344ada..15feb52 100644 --- a/input_reader.py +++ b/input_reader.py @@ -4,21 +4,16 @@ import os import cv2 import numpy as np import escapi -import dshowcapture -import time -import traceback -import gc + +def list_cameras(): + print("Available cameras:") class VideoReader(): - def __init__(self, capture, camera=False): - if os.name == 'nt' and camera: - self.cap = cv2.VideoCapture(capture, cv2.CAP_DSHOW) - else: - self.cap = cv2.VideoCapture(capture) + def __init__(self, capture): + self.cap = cv2.VideoCapture(capture) if self.cap is None: print("The video source cannot be opened") sys.exit(0) - self.name = str(capture) def is_open(self): return self.cap.isOpened() def is_ready(self): @@ -28,22 +23,32 @@ class VideoReader(): def close(self): self.cap.release() -class EscapiReader(VideoReader): +class CameraReader(VideoReader): def __init__(self, capture, width, height, fps): self.device = None self.width = width self.height = height self.fps = fps - self.device = capture - escapi.count_capture_devices() - self.name = str(escapi.device_name(self.device).decode('utf8', 'surrogateescape')) - self.buffer = escapi.init_camera(self.device, self.width, self.height, self.fps) - escapi.do_capture(self.device) + if os.name == 'nt': + escapi.init() + self.device = capture + self.buffer = escapi.init_camera(self.device, self.width, self.height, self.fps) + escapi.do_capture(self.device) + else: + super(CameraReader, self).__init__(capture) + self.cap.set(3, width) + self.cap.set(4, height) def is_open(self): + if self.device is None: + return super(CameraReader, self).is_open() return True def is_ready(self): + if self.device is None: + return super(CameraReader, self).is_ready() return escapi.is_capture_done(self.device) def read(self): + if self.device is None: + return super(CameraReader, self).read() if escapi.is_capture_done(self.device): image = escapi.read(self.device, self.width, self.height, self.buffer) escapi.do_capture(self.device) @@ -51,99 +56,10 @@ class EscapiReader(VideoReader): else: return False, None def close(self): - escapi.deinit_camera(self.device) - -class DShowCaptureReader(VideoReader): - def __init__(self, capture, width, height, fps, use_dshowcapture=True, dcap=None): - self.device = None - self.width = width - self.height = height - self.fps = fps - self.dcap = dcap; - self.device = dshowcapture.DShowCapture() - self.device.get_devices() - info = self.device.get_info() - self.name = info[capture]['name'] - if info[capture]['type'] == "Blackmagic": - self.name = "Blackmagic: " + self.name - if dcap is None or dcap < 0: - dcap = 0 - ret = False - if dcap is None: - ret = self.device.capture_device(capture, self.width, self.height, self.fps) + if self.device is None: + super(CameraReader, self).close() else: - if dcap < 0: - ret = self.device.capture_device_default(capture) - else: - ret = self.device.capture_device_by_dcap(capture, dcap, self.width, self.height, self.fps) - if not ret: - raise Exception("Failed to start capture.") - self.width = self.device.width - self.height = self.device.height - self.fps = self.device.fps - print(f"Camera: \"{self.name}\" Capability ID: {dcap} Resolution: {self.device.width}x{self.device.height} Frame rate: {self.device.fps} Colorspace: {self.device.colorspace} Internal: {self.device.colorspace_internal} Flipped: {self.device.flipped}") - self.timeout = 1000 - def is_open(self): - return self.device.capturing() - def is_ready(self): - return self.device.capturing() - def read(self): - img = None - try: - img = self.device.get_frame(self.timeout) - except: - gc.collect() - img = self.device.get_frame(self.timeout) - if img is None: - return False, None - else: - return True, img - def close(self): - self.device.destroy_capture() - -class OpenCVReader(VideoReader): - def __init__(self, capture, width, height, fps): - self.device = None - self.width = width - self.height = height - self.fps = fps - self.name = str(capture) - super(OpenCVReader, self).__init__(capture, camera=True) - self.cap.set(3, width) - self.cap.set(4, height) - self.cap.set(38, 1) - def is_open(self): - return super(OpenCVReader, self).is_open() - def is_ready(self): - return super(OpenCVReader, self).is_ready() - def read(self): - return super(OpenCVReader, self).read() - def close(self): - super(OpenCVReader, self).close() - -class V4L2Reader(OpenCVReader): - def __init__(self, capture, width, height, fps, dformat): - self.cap = cv2.VideoCapture(capture, cv2.CAP_V4L2) - if dformat: - fourcc = cv2.VideoWriter.fourcc(*dformat) - self.cap.set(6, fourcc) - self.device = None - self.width = width - self.height = height - self.fps = fps - self.name = str(capture) - self.cap.set(3, width) - self.cap.set(4, height) - self.cap.set(38, 1) - self.cap.set(5, fps) - def is_open(self): - return super(V4L2Reader, self).is_open() - def is_ready(self): - return super(V4L2Reader, self).is_ready() - def read(self): - return super(V4L2Reader, self).read() - def close(self): - super(V4L2Reader, self).close() + escapi.deinit_camera(self.device) class RawReader: def __init__(self, width, height): @@ -171,101 +87,16 @@ class RawReader: def close(self): self.open = False -def try_int(s): - try: - return int(s) - except: - return None - -def test_reader(reader): - got_any = 0 - try: - for i in range(30): - if not reader.is_ready(): - time.sleep(0.02) - ret, frame = reader.read() - if not ret: - time.sleep(0.02) - print("No frame") - else: - print("Got frame") - got_any += 1 - if got_any > 10: - break - if reader.is_open(): - return got_any > 0 - print("Fail") - return False - except: - traceback.print_exc() - print("Except") - return False - class InputReader(): - def __init__(self, capture, raw_rgb, width, height, fps, use_dshowcapture=False, dcap=None): + def __init__(self, capture, raw_rgb, width, height, fps): self.reader = None - self.name = str(capture) try: if raw_rgb > 0: self.reader = RawReader(width, height) elif os.path.exists(capture): self.reader = VideoReader(capture) - elif capture == str(try_int(capture)): - if os.name == 'nt': - # Try with DShowCapture - good = True - name = "" - try: - if use_dshowcapture: - self.reader = DShowCaptureReader(int(capture), width, height, fps, dcap=dcap) - name = self.reader.name - good = test_reader(self.reader) - self.name = name - else: - good = False - except: - print("DShowCapture exception: ") - traceback.print_exc() - good = False - if good: - return - # Try with Escapi - good = True - try: - print(f"DShowCapture failed. Falling back to escapi for device {name}.", file=sys.stderr) - escapi.init() - devices = escapi.count_capture_devices() - found = None - for i in range(devices): - escapi_name = str(escapi.device_name(i).decode('utf8', 'surrogateescape')) - if name == escapi_name: - found = i - if found is None: - good = False - else: - print(f"Found device {name} as {i}.", file=sys.stderr) - self.reader = EscapiReader(found, width, height, fps) - good = test_reader(self.reader) - except: - print("Escapi exception: ") - traceback.print_exc() - good = False - if good: - return - # Try with OpenCV - print(f"Escapi failed. Falling back to OpenCV. If this fails, please change your camera settings.", file=sys.stderr) - self.reader = OpenCVReader(int(capture), width, height, fps) - self.name = self.reader.name - elif sys.platform == 'linux': - try: - self.reader = V4L2Reader(int(capture), width, height, fps, dcap) - except: - print("V4L2 exception: ") - traceback.print_exc() - print(f"V4L2 failed. Falling back to OpenCV. If this fails, please change your camera settings.", file=sys.stderr) - self.reader = OpenCVReader(int(capture), width, height, fps) - else: - self.reader = OpenCVReader(int(capture), width, height, fps) + elif capture == str(int(capture)): + self.reader = CameraReader(int(capture), width, height, fps) except Exception as e: print("Error: " + str(e)) diff --git a/make_exe.bat b/make_exe.bat index 762442b..92a98b6 100644 --- a/make_exe.bat +++ b/make_exe.bat @@ -1,31 +1,9 @@ -echo "Started" +REM pyinstaller --onefile ^ +REM --add-binary escapi/escapi_x86.dll;. ^ +REM --add-binary escapi/escapi_x64.dll;. ^ +REM facetracker.py -:: A venv is used so it's easy to add the onnxruntime dll to the binary - -echo "Creating venv" -python -m venv venv - -echo "Activating venv" -call venv\Scripts\activate.bat - -echo "Installing dependencies" -pip install wheel - -pip install onnxruntime opencv-python==4.5.4.60 pillow numpy==1.23.0 pyinstaller - -echo "Running pyinstaller" -pyinstaller facetracker.py --clean ^ - --onedir ^ - --add-binary dshowcapture/*.dll;. ^ - --add-binary escapi/*.dll;. ^ - --add-binary venv/lib/site-packages/onnxruntime/capi/*.dll;onnxruntime\capi ^ - --add-binary msvcp140.dll;. ^ - --add-binary vcomp140.dll;. ^ - --add-binary concrt140.dll;. ^ - --add-binary vccorlib140.dll;. ^ - --add-binary run.bat;. - -echo "Deleting opencv dll" -del dist\facetracker\cv2\opencv_videoio_* - -echo "Finished" +pyinstaller --onedir ^ + --add-binary escapi/escapi_x86.dll;. ^ + --add-binary escapi/escapi_x64.dll;. ^ + facetracker.py \ No newline at end of file diff --git a/make_exe.sh b/make_exe.sh deleted file mode 100755 index 1963f23..0000000 --- a/make_exe.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -set -e - -PYTHON_BINARY=$(which python3) - -if [[ -z "$PYTHON_BINARY" ]]; then - echo "python3 not found. Searching for python instead." - PYTHON_BINARY=$(which python) - if [[ -z "$PYTHON_BINARY" ]]; then - echo "Python 3 must be available on your path. Exiting." - exit 1 - fi -fi - -echo "Creating venv" -"$PYTHON_BINARY" -m venv venv - -source venv/bin/activate - -echo "Installing packages" -pip install wheel # Make sure this is installed beforehand - -pip install onnxruntime opencv-python==4.5.4.60 pillow numpy==1.23.0 pyinstaller - -echo "Creating binary" -pyinstaller --onedir --clean facetracker.py \ - --add-binary venv/lib/python3.*/site-packages/onnxruntime/capi/*.so:onnxruntime/capi - -echo "Files should be available in the dist/ folder" -echo "Done!" - diff --git a/model.py b/model.py index 8f769cd..d95a7d2 100644 --- a/model.py +++ b/model.py @@ -1,225 +1,164 @@ # This file is not used by the tracking application and currently outdated import torch import torch.nn as nn -import geffnet.mobilenetv3 # geffnet.mobilenetv3._gen_mobilenet_v3 needs to be patched to return the parameters instead of instantiating the network, based on commit c450c12ae6ffb1757f62dde3c2765da3c10f6def -from geffnet.efficientnet_builder import round_channels class DSConv2d(nn.Module): - def __init__(self, in_planes, out_planes, kernels_per_layer=4, groups=1, old=0): + def __init__(self, in_planes, out_planes, kernels_per_layer=4, groups=1): super(DSConv2d, self).__init__() - if old == 2: - self.conv = nn.Sequential( - nn.Conv2d(in_planes, in_planes * kernels_per_layer, kernel_size=3, padding=1, groups=in_planes), - nn.Conv2d(in_planes * kernels_per_layer, out_planes, kernel_size=1, groups=groups) - ) - elif old == 1: - self.conv = nn.Sequential( - nn.Conv2d(in_planes, in_planes * kernels_per_layer, kernel_size=3, padding=1, groups=in_planes, bias=False), - nn.BatchNorm2d(in_planes * kernels_per_layer), - nn.Conv2d(in_planes * kernels_per_layer, out_planes, kernel_size=1, groups=groups, bias=False), - nn.BatchNorm2d(out_planes), - nn.ReLU6(inplace=True) - ) - else: - self.conv = nn.Sequential( - nn.Conv2d(in_planes, in_planes * kernels_per_layer, kernel_size=3, padding=1, groups=in_planes, bias=False), - nn.BatchNorm2d(in_planes * kernels_per_layer), - nn.ReLU6(inplace=True), - nn.Conv2d(in_planes * kernels_per_layer, out_planes, kernel_size=1, groups=groups, bias=False), - nn.BatchNorm2d(out_planes), - nn.ReLU6(inplace=True) - ) + self.conv = nn.Sequential( + nn.Conv2d(in_planes, in_planes * kernels_per_layer, kernel_size=3, padding=1, groups=in_planes), + nn.Conv2d(in_planes * kernels_per_layer, out_planes, kernel_size=1, groups=groups) + ) def forward(self, x): x = self.conv(x) return x class UNetUp(nn.Module): - def __init__(self, in_channels, residual_in_channels, out_channels, size, old=0): + def __init__(self, in_channels, residual_in_channels, out_channels, size): super(UNetUp, self).__init__() self.up = nn.Upsample(size=size, mode='bilinear', align_corners=True) - self.conv = DSConv2d(in_channels + residual_in_channels, out_channels, 1, 1, old=old) + self.conv = DSConv2d(in_channels + residual_in_channels, out_channels, 1, 1) def forward(self, x1, x2): x1 = self.up(x1) x = torch.cat([x2, x1], dim=1) x = self.conv(x) return x -# This is the gaze tracking model -class OpenSeeFaceGaze(geffnet.mobilenetv3.MobileNetV3): +# Copy of torchvision ShuffleNetV2 for type annotation +def channel_shuffle(x, groups: int): + batchsize, num_channels, height, width = x.data.size() + channels_per_group = num_channels // groups + + # reshape + x = x.view(batchsize, groups, + channels_per_group, height, width) + + x = torch.transpose(x, 1, 2).contiguous() + + # flatten + x = x.view(batchsize, -1, height, width) + + return x + +class InvertedResidual(nn.Module): + def __init__(self, inp, oup, stride): + super(InvertedResidual, self).__init__() + + if not (1 <= stride <= 3): + raise ValueError('illegal stride value') + self.stride = stride + + branch_features = oup // 2 + assert (self.stride != 1) or (inp == branch_features << 1) + + self.branch1 = nn.Sequential( + self.depthwise_conv(inp, inp, kernel_size=3, stride=self.stride, padding=1), + nn.BatchNorm2d(inp), + nn.Conv2d(inp, branch_features, kernel_size=1, stride=1, padding=0, bias=False), + nn.BatchNorm2d(branch_features), + nn.ReLU(inplace=True), + ) + + self.branch2 = nn.Sequential( + nn.Conv2d(inp if (self.stride > 1) else branch_features, + branch_features, kernel_size=1, stride=1, padding=0, bias=False), + nn.BatchNorm2d(branch_features), + nn.ReLU(inplace=True), + self.depthwise_conv(branch_features, branch_features, kernel_size=3, stride=self.stride, padding=1), + nn.BatchNorm2d(branch_features), + nn.Conv2d(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias=False), + nn.BatchNorm2d(branch_features), + nn.ReLU(inplace=True), + ) + + @staticmethod + def depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias=False): + return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i) + + def forward(self, x): + if self.stride == 1: + x1, x2 = x.chunk(2, dim=1) + out = torch.cat((x1, self.branch2(x2)), dim=1) + else: + out = torch.cat((self.branch1(x), self.branch2(x)), dim=1) + + out = channel_shuffle(out, 2) + + return out + +class ShuffleNetV2(nn.Module): + def __init__(self, stages_repeats, stages_out_channels, num_classes=1000): + super(ShuffleNetV2, self).__init__() + + if len(stages_repeats) != 3: + raise ValueError('expected stages_repeats as list of 3 positive ints') + if len(stages_out_channels) != 5: + raise ValueError('expected stages_out_channels as list of 5 positive ints') + self._stage_out_channels = stages_out_channels + + input_channels = 3 + output_channels = self._stage_out_channels[0] + self.conv1 = nn.Sequential( + nn.Conv2d(input_channels, output_channels, 3, 2, 1, bias=False), + nn.BatchNorm2d(output_channels), + nn.ReLU(inplace=True), + ) + input_channels = output_channels + + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + + stage_names = ['stage{}'.format(i) for i in [2, 3, 4]] + for name, repeats, output_channels in zip( + stage_names, stages_repeats, self._stage_out_channels[1:]): + seq = [InvertedResidual(input_channels, output_channels, 2)] + for i in range(repeats - 1): + seq.append(InvertedResidual(output_channels, output_channels, 1)) + setattr(self, name, nn.Sequential(*seq)) + input_channels = output_channels + + output_channels = self._stage_out_channels[-1] + self.conv5 = nn.Sequential( + nn.Conv2d(input_channels, output_channels, 1, 1, 0, bias=False), + nn.BatchNorm2d(output_channels), + nn.ReLU(inplace=True), + ) + + self.fc = nn.Linear(output_channels, num_classes) + + def forward(self, x): + x = self.conv1(x) + x = self.maxpool(x) + x = self.stage2(x) + x = self.stage3(x) + x = self.stage4(x) + x = self.conv5(x) + x = x.mean([2, 3]) # globalpool + x = self.fc(x) + return x + +# Facial landmark detection model +class OpenSeeNetSNV2(ShuffleNetV2): def __init__(self): - kwargs = geffnet.mobilenetv3._gen_mobilenet_v3(['small']) - super(OpenSeeFaceGaze, self).__init__(**kwargs) - self.up1 = UNetUp(576, 48, 64, (2,2), old=2) - self.up2 = UNetUp(64, 24, 32, (4,4), old=2) - self.up3 = UNetUp(32, 16, 15, (8,8), old=2) - self.group = DSConv2d(15, 3, kernels_per_layer=4, groups=3, old=2) + super(OpenSeeNetSNV2, self).__init__([4, 8, 4], [24, 116, 232, 464, 1024]) + self.up1 = UNetUp(1024, 232, 256, (14,14)) + self.up2 = UNetUp(256, 116, 198 * 1, (28,28)) + self.group = DSConv2d(198 * 1, 198, kernels_per_layer=4, groups=3) + def _forward_impl(self, x): - x = self.conv_stem(x) - x = self.bn1(x) - x = self.act1(x) - r1 = None - r2 = None - r3 = None - for i, feature in enumerate(self.blocks): - x = feature(x) - if i == 3: - r3 = x - if i == 1: - r2 = x - if i == 0: - r1 = x + x = self.conv1(x) + x = self.maxpool(x) + x = self.stage2(x) + r2 = x + x = self.stage3(x) + r3 = x + x = self.stage4(x) + x = self.conv5(x) + x = self.up1(x, r3) x = self.up2(x, r2) - x = self.up3(x, r1) x = self.group(x) return x - def forward(self, x): - return self._forward_impl(x) -# This is the face detection model. Because the landmark model is very robust, it gets away with predicting very rough bounding boxes. It is fully convolutional and can be made to run on different resolutions. It was trained on 224x224 crops and the most reasonable results can be found in the range of 224x224 to 640x640. -class OpenSeeFaceDetect(geffnet.mobilenetv3.MobileNetV3): - def __init__(self, size="large", channel_multiplier=0.1): - kwargs = geffnet.mobilenetv3._gen_mobilenet_v3([size], channel_multiplier=channel_multiplier) - super(OpenSeeFaceDetect, self).__init__(**kwargs) - if size == "large": - self.up1 = UNetUp(round_channels(960, channel_multiplier), round_channels(112, channel_multiplier), 256, (14,14), old=1) - self.up2 = UNetUp(256, round_channels(40, channel_multiplier), 128, (28,28), old=1) - self.up3 = UNetUp(128, round_channels(24, channel_multiplier), 64, (56,56), old=1) - self.group = DSConv2d(64, 2, kernels_per_layer=4, groups=2, old=1) - self.r1_i = 1 - self.r2_i = 2 - self.r3_i = 4 - elif size == "small": - self.up1 = UNetUp(round_channels(576, channel_multiplier), round_channels(40, channel_multiplier), 256, (14,14), old=1) - self.up2 = UNetUp(256, round_channels(24, channel_multiplier), 128, (28,28), old=1) - self.up3 = UNetUp(128, round_channels(16, channel_multiplier), 64, (56,56), old=1) - self.group = DSConv2d(64, 2, kernels_per_layer=4, groups=2, old=1) - self.r1_i = 0 - self.r2_i = 1 - self.r3_i = 2 - self.maxpool = nn.MaxPool2d(kernel_size=3, dilation=1, stride=1, padding=1) - def _forward_impl(self, x): - x = self.conv_stem(x) - x = self.bn1(x) - x = self.act1(x) - r2 = None - r3 = None - for i, feature in enumerate(self.blocks): - x = feature(x) - if i == self.r3_i: - r3 = x - if i == self.r2_i: - r2 = x - if i == self.r1_i: - r1 = x - x = self.up1(x, r3) - x = self.up2(x, r2) - x = self.up3(x, r1) - x = self.group(x) - x2 = self.maxpool(x) - return x, x2 - def forward(self, x): - return self._forward_impl(x) - -def logit_arr(p, factor=16.0): - p = p.clamp(0.0000001, 0.9999999) - return torch.log(p / (1 - p)) / factor - -# Landmark detection model -# Models: -# 0: "small", 0.5 -# 1: "small", 1.0 -# 2: "large", 0.75 -# 3: "large", 1.0 -class OpenSeeFaceLandmarks(geffnet.mobilenetv3.MobileNetV3): - def __init__(self, size="large", channel_multiplier=1.0, inference=False): - kwargs = geffnet.mobilenetv3._gen_mobilenet_v3([size], channel_multiplier=channel_multiplier) - super(OpenSeeFaceLandmarks, self).__init__(**kwargs) - if size == "large": - self.up1 = UNetUp(round_channels(960, channel_multiplier), round_channels(112, channel_multiplier), 256, (14,14)) - self.up2 = UNetUp(256, round_channels(40, channel_multiplier), 198 * 1, (28,28)) - self.group = DSConv2d(198 * 1, 198, kernels_per_layer=4, groups=3) - self.r2_i = 2 - self.r3_i = 4 - elif size == "small": - self.up1 = UNetUp(round_channels(576, channel_multiplier), round_channels(40, channel_multiplier), 256, (14,14)) - self.up2 = UNetUp(256, round_channels(24, channel_multiplier), 198 * 1, (28,28)) - self.group = DSConv2d(198 * 1, 198, kernels_per_layer=4, groups=3) - self.r2_i = 1 - self.r3_i = 2 - self.inference = inference - def _forward_impl(self, x): - x = self.conv_stem(x) - x = self.bn1(x) - x = self.act1(x) - r2 = None - r3 = None - for i, feature in enumerate(self.blocks): - x = feature(x) - if i == self.r3_i: - r3 = x - if i == self.r2_i: - r2 = x - x = self.up1(x, r3) - x = self.up2(x, r2) - x = self.group(x) - - if self.inference: - t_main = x[:, 0:66].reshape((-1, 66, 28*28)) - t_m = t_main.argmax(dim=2) - indices = t_m.unsqueeze(2) - t_conf = t_main.gather(2, indices).squeeze(2) - t_off_x = x[:, 66:132].reshape((-1, 66, 28*28)).gather(2, indices).squeeze(2) - t_off_y = x[:, 132:198].reshape((-1, 66, 28*28)).gather(2, indices).squeeze(2) - t_off_x = (223. * logit_arr(t_off_x) + 0.5).floor() - t_off_y = (223. * logit_arr(t_off_y) + 0.5).floor() - t_x = 223. * (t_m / 28.).floor() / 27. + t_off_x - t_y = 223. * t_m.remainder(28.).float() / 27. + t_off_y - x = (t_conf.mean(1), torch.stack([t_x, t_y, t_conf], 2)) - - return x - def forward(self, x): - return self._forward_impl(x) - -# lm_modelT for 56x56 30 point inference -class OpenSeeFaceLandmarks30Pt(geffnet.mobilenetv3.MobileNetV3): - def __init__(self, size="large", channel_multiplier=1.0, inference=False): - kwargs = geffnet.mobilenetv3._gen_mobilenet_v3([size], channel_multiplier=channel_multiplier) - super(OpenSeeFaceLandmarks30Pt, self).__init__(**kwargs) - self.up1 = UNetUp(960, 112, 256, (4,4)) - self.up2 = UNetUp(256, 40, 180, (7,7)) - self.group = DSConv2d(180, 90, kernels_per_layer=4, groups=3) - self.inference = inference - def _forward_impl(self, x): - x = self.conv_stem(x) - x = self.bn1(x) - x = self.act1(x) - r2 = None - r3 = None - for i, feature in enumerate(self.blocks): - x = feature(x) - if i == 4: - r3 = x - if i == 2: - r2 = x - x = self.up1(x, r3) - x = self.up2(x, r2) - x = self.group(x) - - if self.inference: - t_main = x[:, 0:30].reshape((-1, 30, 7*7)) - t_m = t_main.argmax(dim=2) - indices = t_m.unsqueeze(2) - t_conf = t_main.gather(2, indices).squeeze(2) - t_off_x = x[:, 30:60].reshape((-1, 30, 7*7)).gather(2, indices).squeeze(2) - t_off_y = x[:, 60:90].reshape((-1, 30, 7*7)).gather(2, indices).squeeze(2) - t_off_x = 55. * logit_arr(t_off_x, factor=8.0) - t_off_y = 55. * logit_arr(t_off_y, factor=8.0) - t_x = 55. * (t_m / 7.).floor() / 6. + t_off_x - t_y = 55. * t_m.remainder(7.).float() / 6. + t_off_y - x = (t_conf.mean(1), torch.stack([t_x, t_y, t_conf], 2)) - - return x def forward(self, x): return self._forward_impl(x) @@ -251,21 +190,18 @@ def AdapWingLoss(pre_hm, gt_hm): img_dilate = cv2.morphologyEx(img_merge, cv2.MORPH_DILATE, kernel) img_dilate[img_dilate < 51] = 1 # 0*W+1 img_dilate[img_dilate >= 51] = 11 # 1*W+1 - img_dilate = np.array(img_dilate, dtype=int) + img_dilate = np.array(img_dilate, dtype=np.int) img_dilate = img_dilate.transpose(2, 0, 1) dilated = torch.from_numpy(img_dilate).float() if first: first_mask = dilated first = False - # These weights varied between training runs and model sizes - dilated[17:27][dilated[17:27] > 1] *= 1.4 - dilated[17, dilated[17] > 1] *= 1.6 - dilated[18, dilated[18] > 1] *= 1.8 - dilated[25, dilated[25] > 1] *= 1.8 - dilated[26, dilated[26] > 1] *= 1.6 - dilated[36:48][dilated[36:48] > 1] *= 2.8 - # Used for a very small model - #dilated[[37,38,40,41,43,44,46,47]][dilated[[37,38,40,41,43,44,46,47]] > 1] *= 20.8 + dilated[17:27] *= 1.2 + dilated[17] *= 1.3 + dilated[18] *= 1.4 + dilated[25] *= 1.4 + dilated[26] *= 1.3 + dilated[36:47] *= 2.5 mask[i] = torch.cat([dilated, dilated, dilated], 0) diff_hm = torch.abs(gt_hm - pre_hm) @@ -280,35 +216,5 @@ def AdapWingLoss(pre_hm, gt_hm): return first_mask.detach(), mean_loss - - -# Checkpoint test -if __name__== "__main__": - print("Checking gaze model") - m=OpenSeeFaceGaze() - ckpt = torch.load("gaze.pth") - m.load_state_dict(ckpt) - print("Checking detection model") - m=OpenSeeFaceDetect() - ckpt = torch.load("detection.pth") - m.load_state_dict(ckpt) - print("Checking lm_model0 model") - m=OpenSeeFaceLandmarks("small", 0.5) - ckpt = torch.load("lm_model0.pth") - m.load_state_dict(ckpt) - print("Checking lm_model1 model") - m=OpenSeeFaceLandmarks("small", 1.0) - ckpt = torch.load("lm_model1.pth") - m.load_state_dict(ckpt) - print("Checking lm_model2 model") - m=OpenSeeFaceLandmarks("large", 0.75) - ckpt = torch.load("lm_model2.pth") - m.load_state_dict(ckpt) - print("Checking lm_model3 model") - m=OpenSeeFaceLandmarks("large", 1.0) - ckpt = torch.load("lm_model3.pth") - m.load_state_dict(ckpt) - print("Checking lm_modelT model") - m=OpenSeeFaceLandmarks("large", 1.0) - ckpt = torch.load("lm_modelT.pth") - m.load_state_dict(ckpt) +# The fast model runs on grayscale 112x112 using the ShuffleNet V2 0.5x configuration with input_channels=1. It was trained using AWL, but without the additional weighting for certain features +. \ No newline at end of file diff --git a/models/benchmark.bin b/models/benchmark.bin deleted file mode 100644 index 04fb818..0000000 Binary files a/models/benchmark.bin and /dev/null differ diff --git a/models/lm_model4_opt.onnx b/models/lm_model4_opt.onnx deleted file mode 100644 index cc92fc0..0000000 Binary files a/models/lm_model4_opt.onnx and /dev/null differ diff --git a/models/lm_modelT_opt.onnx b/models/lm_modelT_opt.onnx deleted file mode 100644 index 27b03c8..0000000 Binary files a/models/lm_modelT_opt.onnx and /dev/null differ diff --git a/models/lm_modelU_opt.onnx b/models/lm_modelU_opt.onnx deleted file mode 100644 index b0a5432..0000000 Binary files a/models/lm_modelU_opt.onnx and /dev/null differ diff --git a/models/lm_modelV_opt.onnx b/models/lm_modelV_opt.onnx deleted file mode 100644 index a966879..0000000 Binary files a/models/lm_modelV_opt.onnx and /dev/null differ diff --git a/models/lm_model3_opt.onnx b/models/mnv3_opt_b.onnx similarity index 100% rename from models/lm_model3_opt.onnx rename to models/mnv3_opt_b.onnx diff --git a/models/lm_model1_opt.onnx b/models/mnv3_opt_fast.onnx similarity index 100% rename from models/lm_model1_opt.onnx rename to models/mnv3_opt_fast.onnx diff --git a/models/lm_model2_opt.onnx b/models/mnv3_opt_medium.onnx similarity index 100% rename from models/lm_model2_opt.onnx rename to models/mnv3_opt_medium.onnx diff --git a/models/lm_model0_opt.onnx b/models/mnv3_opt_very_fast.onnx similarity index 100% rename from models/lm_model0_opt.onnx rename to models/mnv3_opt_very_fast.onnx diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index ffcd882..0000000 --- a/poetry.lock +++ /dev/null @@ -1,224 +0,0 @@ -[[package]] -name = "flatbuffers" -version = "2.0" -description = "The FlatBuffers serialization format for Python" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "numpy" -version = "1.22" -description = "NumPy is the fundamental package for array computing with Python." -category = "main" -optional = false -python-versions = ">=3.7,<3.11" - -[[package]] -name = "onnxruntime" -version = "1.9.0" -description = "ONNX Runtime is a runtime accelerator for Machine Learning models" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -flatbuffers = "*" -numpy = ">=1.16.6" -protobuf = "*" - -[[package]] -name = "opencv-python" -version = "4.5.4.58" -description = "Wrapper package for OpenCV python bindings." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -numpy = ">=1.21.2" - -[[package]] -name = "pillow" -version = "10.2.0" -description = "Python Imaging Library (Fork)" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "protobuf" -version = "4.25.8" -description = "Protocol Buffers" -category = "main" -optional = false -python-versions = ">=3.5" - -[metadata] -lock-version = "1.1" -python-versions = ">=3.7,<3.11" -content-hash = "1511681290c580145b1117beffe728052d856eee3ad8419930626c6fc6c9a09d" - -[metadata.files] -flatbuffers = [ - {file = "flatbuffers-2.0-py2.py3-none-any.whl", hash = "sha256:3751954f0604580d3219ae49a85fafec9d85eec599c0b96226e1bc0b48e57474"}, - {file = "flatbuffers-2.0.tar.gz", hash = "sha256:12158ab0272375eab8db2d663ae97370c33f152b27801fa6024e1d6105fd4dd2"}, -] -numpy = [ - {file = "numpy-1.21.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:508b0b513fa1266875524ba8a9ecc27b02ad771fe1704a16314dc1a816a68737"}, - {file = "numpy-1.21.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5dfe9d6a4c39b8b6edd7990091fea4f852888e41919d0e6722fe78dd421db0eb"}, - {file = "numpy-1.21.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a10968963640e75cc0193e1847616ab4c718e83b6938ae74dea44953950f6b7"}, - {file = "numpy-1.21.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c6249260890e05b8111ebfc391ed58b3cb4b33e63197b2ec7f776e45330721"}, - {file = "numpy-1.21.3-cp310-cp310-win_amd64.whl", hash = "sha256:f8f4625536926a155b80ad2bbff44f8cc59e9f2ad14cdda7acf4c135b4dc8ff2"}, - {file = "numpy-1.21.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e54af82d68ef8255535a6cdb353f55d6b8cf418a83e2be3569243787a4f4866f"}, - {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f41b018f126aac18583956c54544db437f25c7ee4794bcb23eb38bef8e5e192a"}, - {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:50cd26b0cf6664cb3b3dd161ba0a09c9c1343db064e7c69f9f8b551f5104d654"}, - {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cc9b512e9fb590797474f58b7f6d1f1b654b3a94f4fa8558b48ca8b3cfc97cf"}, - {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:88a5d6b268e9ad18f3533e184744acdaa2e913b13148160b1152300c949bbb5f"}, - {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3c09418a14471c7ae69ba682e2428cae5b4420a766659605566c0fa6987f6b7e"}, - {file = "numpy-1.21.3-cp37-cp37m-win32.whl", hash = "sha256:90bec6a86b348b4559b6482e2b684db4a9a7eed1fa054b86115a48d58fbbf62a"}, - {file = "numpy-1.21.3-cp37-cp37m-win_amd64.whl", hash = "sha256:043e83bfc274649c82a6f09836943e4a4aebe5e33656271c7dbf9621dd58b8ec"}, - {file = "numpy-1.21.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:75621882d2230ab77fb6a03d4cbccd2038511491076e7964ef87306623aa5272"}, - {file = "numpy-1.21.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:188031f833bbb623637e66006cf75e933e00e7231f67e2b45cf8189612bb5dc3"}, - {file = "numpy-1.21.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:160ccc1bed3a8371bf0d760971f09bfe80a3e18646620e9ded0ad159d9749baa"}, - {file = "numpy-1.21.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:29fb3dcd0468b7715f8ce2c0c2d9bbbaf5ae686334951343a41bd8d155c6ea27"}, - {file = "numpy-1.21.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:32437f0b275c1d09d9c3add782516413e98cd7c09e6baf4715cbce781fc29912"}, - {file = "numpy-1.21.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e606e6316911471c8d9b4618e082635cfe98876007556e89ce03d52ff5e8fcf0"}, - {file = "numpy-1.21.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a99a6b067e5190ac6d12005a4d85aa6227c5606fa93211f86b1dafb16233e57d"}, - {file = "numpy-1.21.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dde972a1e11bb7b702ed0e447953e7617723760f420decb97305e66fb4afc54f"}, - {file = "numpy-1.21.3-cp38-cp38-win32.whl", hash = "sha256:fe52dbe47d9deb69b05084abd4b0df7abb39a3c51957c09f635520abd49b29dd"}, - {file = "numpy-1.21.3-cp38-cp38-win_amd64.whl", hash = "sha256:75eb7cadc8da49302f5b659d40ba4f6d94d5045fbd9569c9d058e77b0514c9e4"}, - {file = "numpy-1.21.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2a6ee9620061b2a722749b391c0d80a0e2ae97290f1b32e28d5a362e21941ee4"}, - {file = "numpy-1.21.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c4193f70f8069550a1788bd0cd3268ab7d3a2b70583dfe3b2e7f421e9aace06"}, - {file = "numpy-1.21.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f15209fb535dd4c504a7762d3bc440779b0e37d50ed810ced209e5cea60d96"}, - {file = "numpy-1.21.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c6c2d535a7beb1f8790aaa98fd089ceab2e3dd7ca48aca0af7dc60e6ef93ffe1"}, - {file = "numpy-1.21.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bffa2eee3b87376cc6b31eee36d05349571c236d1de1175b804b348dc0941e3f"}, - {file = "numpy-1.21.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc14e7519fab2a4ed87d31f99c31a3796e4e1fe63a86ebdd1c5a1ea78ebd5896"}, - {file = "numpy-1.21.3-cp39-cp39-win32.whl", hash = "sha256:dd0482f3fc547f1b1b5d6a8b8e08f63fdc250c58ce688dedd8851e6e26cff0f3"}, - {file = "numpy-1.21.3-cp39-cp39-win_amd64.whl", hash = "sha256:300321e3985c968e3ae7fbda187237b225f3ffe6528395a5b7a5407f73cf093e"}, - {file = "numpy-1.21.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98339aa9911853f131de11010f6dd94c8cec254d3d1f7261528c3b3e3219f139"}, - {file = "numpy-1.21.3.zip", hash = "sha256:63571bb7897a584ca3249c86dd01c10bcb5fe4296e3568b2e9c1a55356b6410e"}, -] -onnxruntime = [ - {file = "onnxruntime-1.9.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:48f0fcf3c9aa6836584e64abe63fa7395c02066d3259bbdeb489b4d172e0127a"}, - {file = "onnxruntime-1.9.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f9d772a6330cb85e7723f84e357320a1603e3824a92aab4ef36fc3a41e64f16"}, - {file = "onnxruntime-1.9.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3bdb861822a63404cca7b46dce86d48bbc21c906a4b4ed13969bc89763ac7f96"}, - {file = "onnxruntime-1.9.0-cp36-cp36m-win32.whl", hash = "sha256:e3f8f7d5d4d66e3a4a2b731a000d3142a53a5403e8814e68bbd659514e815899"}, - {file = "onnxruntime-1.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:cf3edbc54bfe99a119d73cd65398a2ec68ae3af2557ab7e645976314a8d11aa1"}, - {file = "onnxruntime-1.9.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:c8ff9c914b2b1c3b022dedc199e3f971e340d8923a1ef42d66530508fa367bf6"}, - {file = "onnxruntime-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d03ff4a2717c4149acc7c649fd66a67e81ec44c9e6e2a00df1d6e9ca843f1b7"}, - {file = "onnxruntime-1.9.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8a2315e2244ac371742f6e30da5367c680c3e84c31e291a35f8ddfab09c3c82"}, - {file = "onnxruntime-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:fa927b1825f2851c0c8f3948515a56d76cb0686da9acd1d6f8fafe552c8d8fec"}, - {file = "onnxruntime-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9ccaf6a0365f2b86efe21681416b8cfe97f084a7d53bd1cf2bf889a0aef2b0d3"}, - {file = "onnxruntime-1.9.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:d20ce3448babe89a77cc9d357730767deb3617e36439bddcd006f28abc72b416"}, - {file = "onnxruntime-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd1d6647245aa38e1099cfd355d84e807de5350d5216e84ceefd91c64ce243d"}, - {file = "onnxruntime-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f00620fc0f51bc4d90ae6d96ceb4b6538e3bd1e328178104118ac672f37c40d"}, - {file = "onnxruntime-1.9.0-cp38-cp38-win32.whl", hash = "sha256:e1c1fe3f7d960eeffc02a5f196d85529254eefd59cbeecd8abee0a9467b5c2d8"}, - {file = "onnxruntime-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9002214af1b2317ab3a63a2f045f7d1363c207e661d475a877aa6499ca09d606"}, - {file = "onnxruntime-1.9.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:7339cef9b918b88f1fec8109cfa0a8416f119c5968d00300a9186847d86e35de"}, - {file = "onnxruntime-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdec8538eb59e63a376d0677f7ec043ceb597d52ee88f1f7e250928893a0de7f"}, - {file = "onnxruntime-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab62b29429e0e62c11478b2a8a3af2646531fba7800736e8b201d8baa50b43a8"}, - {file = "onnxruntime-1.9.0-cp39-cp39-win32.whl", hash = "sha256:4aee9a893f93637341fd0e6b56fa3ab1c430d718d08d79a358603297a1575ad9"}, - {file = "onnxruntime-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:bdf1327932227383b04093a51266474b2703b3fcf9c0f6f11c652d9652b76a5c"}, -] -opencv-python = [ - {file = "opencv-python-4.5.4.58.tar.gz", hash = "sha256:48288428f407bacba5f73d460feb4a1ecafe87db3d7cfc0730a49fb32f589bbf"}, - {file = "opencv_python-4.5.4.58-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0eba0bfe62c48a02a5af3a0944e872c99f57f98653bed14d51c6991a58f9e1d1"}, - {file = "opencv_python-4.5.4.58-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:9bcca50c5444b5cfb01624666b69f91ba8f2d2bf4ef37b111697aafdeb81c99f"}, - {file = "opencv_python-4.5.4.58-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:8f7886acabaebf0361bd3dbccaa0d08e3f65ab13b7c739eb11e028f01ad13582"}, - {file = "opencv_python-4.5.4.58-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:d4b1d0b98ee72ba5dd720166790fc93ce459281e138ee79b0d41420b3da52b2e"}, - {file = "opencv_python-4.5.4.58-cp310-cp310-win32.whl", hash = "sha256:69a78e40a374ac14e4bf15a13dbb6c30fd2fbd5fcd3674d020a31b88861d5aaf"}, - {file = "opencv_python-4.5.4.58-cp310-cp310-win_amd64.whl", hash = "sha256:315c357522b6310ef7a0718d9f0c5d3110e59c19140705499a3c29bdd8c0124f"}, - {file = "opencv_python-4.5.4.58-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:887a61097092dc0bf23fa24646dbc8cfeeb753649cb28a3782a93a6879e3b7d2"}, - {file = "opencv_python-4.5.4.58-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:22bcc3153a7d4f95aff79457eef81ef5e40ab1851b189e014412b5e9fbee2573"}, - {file = "opencv_python-4.5.4.58-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:92e9b2261ec764229c948d77fe0d922ee033348ca6519939b87861016c1614b3"}, - {file = "opencv_python-4.5.4.58-cp36-cp36m-win32.whl", hash = "sha256:0d6249a49122a78afc6685ddb1377a87e46414ae61c84535c4c6024397f1f3e8"}, - {file = "opencv_python-4.5.4.58-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa144013b597e4dcabc8d8230edfe810319de01b5609556d415a20e2b707547"}, - {file = "opencv_python-4.5.4.58-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:26feeeb280de179f5dbb8976ebf7ceb836bd263973cb5daec8ca36e8ef7b5773"}, - {file = "opencv_python-4.5.4.58-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:4a13381bdfc0fb4b080efcc27c46561d0bd752f126226e9f19aa9cbcf6677f40"}, - {file = "opencv_python-4.5.4.58-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:ac852fcaac93439f2f7116ddffdc23fd366c872200ade2272446f9898180cecb"}, - {file = "opencv_python-4.5.4.58-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02872e0a9358526646d691f390143e9c21109c210095314abaa0641211cda077"}, - {file = "opencv_python-4.5.4.58-cp37-cp37m-win32.whl", hash = "sha256:6b87bab220d17e03eeedbcc6652d9d7e7bb09886dbd0f810310697a948b4c6fd"}, - {file = "opencv_python-4.5.4.58-cp37-cp37m-win_amd64.whl", hash = "sha256:a2a7f09b8843b85f3e1b02c5ea3ddc0cb9f5ad9698380109b37069ee8db7746d"}, - {file = "opencv_python-4.5.4.58-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:c44f5c51e92322ed832607204249c190764dec6cf29e8ba6d679b10326be1c1b"}, - {file = "opencv_python-4.5.4.58-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9b2c198af083a693d42a82bddc4d1f7e6bb02c64192ff7fac1fd1d43a8cf1be6"}, - {file = "opencv_python-4.5.4.58-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:637f4d3ad81bd27f273ede4c5fa6c26afb85c097c9715baf107cc270e37f5fea"}, - {file = "opencv_python-4.5.4.58-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:2fff48a641a74d1def31c1e88f9e5ce50ba4d0f87d085dfbf8bc844e12f6cd54"}, - {file = "opencv_python-4.5.4.58-cp38-cp38-win32.whl", hash = "sha256:8ddf4dcd8199209e33f21deb0c6d8ab62b21802816bba895fefc346b6d2e522d"}, - {file = "opencv_python-4.5.4.58-cp38-cp38-win_amd64.whl", hash = "sha256:085c5fcf5a6479c34aca3fd0f59055e704083d6a44009d6583c675ff1a5a0625"}, - {file = "opencv_python-4.5.4.58-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4abe9c4fb6fe16daa9fcdd68b5357d3530431341aa655203f8e84f394e1fe6d4"}, - {file = "opencv_python-4.5.4.58-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b614fbd81aeda53ce28e645aaee18fda7c7f2a48eb7f1a70a7c6c3427946342"}, - {file = "opencv_python-4.5.4.58-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215bdf069847d4e3b0447a34e9eb4046dd4ca523d41fe4381c1c55f6704fd0dc"}, - {file = "opencv_python-4.5.4.58-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc34cdbfbab463750713118c8259a5d364547adab8ed91e94ba888349f33590a"}, - {file = "opencv_python-4.5.4.58-cp39-cp39-win32.whl", hash = "sha256:9998ce60884f3cda074f02b56d2b57ee6bd863e2ddba132da2b0af3b9487d584"}, - {file = "opencv_python-4.5.4.58-cp39-cp39-win_amd64.whl", hash = "sha256:5370a11757fbe94b176771269aff599f4da8676c2a672b13bcbca043f2e3eea8"}, -] -pillow = [ - {file = "Pillow-8.4.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d"}, - {file = "Pillow-8.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f97cfb1e5a392d75dd8b9fd274d205404729923840ca94ca45a0af57e13dbe6"}, - {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb9fc393f3c61f9054e1ed26e6fe912c7321af2f41ff49d3f83d05bacf22cc78"}, - {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d82cdb63100ef5eedb8391732375e6d05993b765f72cb34311fab92103314649"}, - {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc1afda735a8d109007164714e73771b499768b9bb5afcbbee9d0ff374b43f"}, - {file = "Pillow-8.4.0-cp310-cp310-win32.whl", hash = "sha256:e3dacecfbeec9a33e932f00c6cd7996e62f53ad46fbe677577394aaa90ee419a"}, - {file = "Pillow-8.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:620582db2a85b2df5f8a82ddeb52116560d7e5e6b055095f04ad828d1b0baa39"}, - {file = "Pillow-8.4.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:1bc723b434fbc4ab50bb68e11e93ce5fb69866ad621e3c2c9bdb0cd70e345f55"}, - {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72cbcfd54df6caf85cc35264c77ede902452d6df41166010262374155947460c"}, - {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70ad9e5c6cb9b8487280a02c0ad8a51581dcbbe8484ce058477692a27c151c0a"}, - {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25a49dc2e2f74e65efaa32b153527fc5ac98508d502fa46e74fa4fd678ed6645"}, - {file = "Pillow-8.4.0-cp36-cp36m-win32.whl", hash = "sha256:93ce9e955cc95959df98505e4608ad98281fff037350d8c2671c9aa86bcf10a9"}, - {file = "Pillow-8.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2e4440b8f00f504ee4b53fe30f4e381aae30b0568193be305256b1462216feff"}, - {file = "Pillow-8.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8c803ac3c28bbc53763e6825746f05cc407b20e4a69d0122e526a582e3b5e153"}, - {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8a17b5d948f4ceeceb66384727dde11b240736fddeda54ca740b9b8b1556b29"}, - {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1394a6ad5abc838c5cd8a92c5a07535648cdf6d09e8e2d6df916dfa9ea86ead8"}, - {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:792e5c12376594bfcb986ebf3855aa4b7c225754e9a9521298e460e92fb4a488"}, - {file = "Pillow-8.4.0-cp37-cp37m-win32.whl", hash = "sha256:d99ec152570e4196772e7a8e4ba5320d2d27bf22fdf11743dd882936ed64305b"}, - {file = "Pillow-8.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:7b7017b61bbcdd7f6363aeceb881e23c46583739cb69a3ab39cb384f6ec82e5b"}, - {file = "Pillow-8.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:d89363f02658e253dbd171f7c3716a5d340a24ee82d38aab9183f7fdf0cdca49"}, - {file = "Pillow-8.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a0956fdc5defc34462bb1c765ee88d933239f9a94bc37d132004775241a7585"}, - {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b7bb9de00197fb4261825c15551adf7605cf14a80badf1761d61e59da347779"}, - {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72b9e656e340447f827885b8d7a15fc8c4e68d410dc2297ef6787eec0f0ea409"}, - {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5a4532a12314149d8b4e4ad8ff09dde7427731fcfa5917ff16d0291f13609df"}, - {file = "Pillow-8.4.0-cp38-cp38-win32.whl", hash = "sha256:82aafa8d5eb68c8463b6e9baeb4f19043bb31fefc03eb7b216b51e6a9981ae09"}, - {file = "Pillow-8.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:066f3999cb3b070a95c3652712cffa1a748cd02d60ad7b4e485c3748a04d9d76"}, - {file = "Pillow-8.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:5503c86916d27c2e101b7f71c2ae2cddba01a2cf55b8395b0255fd33fa4d1f1a"}, - {file = "Pillow-8.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4acc0985ddf39d1bc969a9220b51d94ed51695d455c228d8ac29fcdb25810e6e"}, - {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b052a619a8bfcf26bd8b3f48f45283f9e977890263e4571f2393ed8898d331b"}, - {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:493cb4e415f44cd601fcec11c99836f707bb714ab03f5ed46ac25713baf0ff20"}, - {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8831cb7332eda5dc89b21a7bce7ef6ad305548820595033a4b03cf3091235ed"}, - {file = "Pillow-8.4.0-cp39-cp39-win32.whl", hash = "sha256:5e9ac5f66616b87d4da618a20ab0a38324dbe88d8a39b55be8964eb520021e02"}, - {file = "Pillow-8.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:3eb1ce5f65908556c2d8685a8f0a6e989d887ec4057326f6c22b24e8a172c66b"}, - {file = "Pillow-8.4.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ddc4d832a0f0b4c52fff973a0d44b6c99839a9d016fe4e6a1cb8f3eea96479c2"}, - {file = "Pillow-8.4.0-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3e5ddc44c14042f0844b8cf7d2cd455f6cc80fd7f5eefbe657292cf601d9ad"}, - {file = "Pillow-8.4.0-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70e94281588ef053ae8998039610dbd71bc509e4acbc77ab59d7d2937b10698"}, - {file = "Pillow-8.4.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:3862b7256046fcd950618ed22d1d60b842e3a40a48236a5498746f21189afbbc"}, - {file = "Pillow-8.4.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4901622493f88b1a29bd30ec1a2f683782e57c3c16a2dbc7f2595ba01f639df"}, - {file = "Pillow-8.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84c471a734240653a0ec91dec0996696eea227eafe72a33bd06c92697728046b"}, - {file = "Pillow-8.4.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:244cf3b97802c34c41905d22810846802a3329ddcb93ccc432870243211c79fc"}, - {file = "Pillow-8.4.0.tar.gz", hash = "sha256:b8e2f83c56e141920c39464b852de3719dfbfb6e3c99a2d8da0edf4fb33176ed"}, -] -protobuf = [ - {file = "protobuf-3.19.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d80f80eb175bf5f1169139c2e0c5ada98b1c098e2b3c3736667f28cbbea39fc8"}, - {file = "protobuf-3.19.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a529e7df52204565bcd33738a7a5f288f3d2d37d86caa5d78c458fa5fabbd54d"}, - {file = "protobuf-3.19.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28ccea56d4dc38d35cd70c43c2da2f40ac0be0a355ef882242e8586c6d66666f"}, - {file = "protobuf-3.19.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b30a7de128c46b5ecb343917d9fa737612a6e8280f440874e5cc2ba0d79b8f6"}, - {file = "protobuf-3.19.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5935c8ce02e3d89c7900140a8a42b35bc037ec07a6aeb61cc108be8d3c9438a6"}, - {file = "protobuf-3.19.1-cp36-cp36m-win32.whl", hash = "sha256:74f33edeb4f3b7ed13d567881da8e5a92a72b36495d57d696c2ea1ae0cfee80c"}, - {file = "protobuf-3.19.1-cp36-cp36m-win_amd64.whl", hash = "sha256:038daf4fa38a7e818dd61f51f22588d61755160a98db087a046f80d66b855942"}, - {file = "protobuf-3.19.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e51561d72efd5bd5c91490af1f13e32bcba8dab4643761eb7de3ce18e64a853"}, - {file = "protobuf-3.19.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:6e8ea9173403219239cdfd8d946ed101f2ab6ecc025b0fda0c6c713c35c9981d"}, - {file = "protobuf-3.19.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db3532d9f7a6ebbe2392041350437953b6d7a792de10e629c1e4f5a6b1fe1ac6"}, - {file = "protobuf-3.19.1-cp37-cp37m-win32.whl", hash = "sha256:615b426a177780ce381ecd212edc1e0f70db8557ed72560b82096bd36b01bc04"}, - {file = "protobuf-3.19.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d8919368410110633717c406ab5c97e8df5ce93020cfcf3012834f28b1fab1ea"}, - {file = "protobuf-3.19.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:71b0250b0cfb738442d60cab68abc166de43411f2a4f791d31378590bfb71bd7"}, - {file = "protobuf-3.19.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3cd0458870ea7d1c58e948ac8078f6ba8a7ecc44a57e03032ed066c5bb318089"}, - {file = "protobuf-3.19.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:655264ed0d0efe47a523e2255fc1106a22f6faab7cc46cfe99b5bae085c2a13e"}, - {file = "protobuf-3.19.1-cp38-cp38-win32.whl", hash = "sha256:b691d996c6d0984947c4cf8b7ae2fe372d99b32821d0584f0b90277aa36982d3"}, - {file = "protobuf-3.19.1-cp38-cp38-win_amd64.whl", hash = "sha256:e7e8d2c20921f8da0dea277dfefc6abac05903ceac8e72839b2da519db69206b"}, - {file = "protobuf-3.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fd390367fc211cc0ffcf3a9e149dfeca78fecc62adb911371db0cec5c8b7472d"}, - {file = "protobuf-3.19.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d83e1ef8cb74009bebee3e61cc84b1c9cd04935b72bca0cbc83217d140424995"}, - {file = "protobuf-3.19.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36d90676d6f426718463fe382ec6274909337ca6319d375eebd2044e6c6ac560"}, - {file = "protobuf-3.19.1-cp39-cp39-win32.whl", hash = "sha256:e7b24c11df36ee8e0c085e5b0dc560289e4b58804746fb487287dda51410f1e2"}, - {file = "protobuf-3.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:77d2fadcf369b3f22859ab25bd12bb8e98fb11e05d9ff9b7cd45b711c719c002"}, - {file = "protobuf-3.19.1-py2.py3-none-any.whl", hash = "sha256:e813b1c9006b6399308e917ac5d298f345d95bb31f46f02b60cd92970a9afa17"}, - {file = "protobuf-3.19.1.tar.gz", hash = "sha256:62a8e4baa9cb9e064eb62d1002eca820857ab2138440cb4b3ea4243830f94ca7"}, -] diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index de1cc7b..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,19 +0,0 @@ -[tool.poetry] -name = "openseeface" -version = "1.20.4" -description = "" -authors = ["emilianavt"] -license = "BSD-2-Clause" - -[tool.poetry.dependencies] -python = ">=3.7,<3.11" -numpy = "^1.21.3" -opencv-python = "^4.5.4" -Pillow = "^8.4.0" -onnxruntime = "^1.9.0" - -[tool.poetry.dev-dependencies] - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" diff --git a/retinaface.py b/retinaface.py index b1d1ae5..c97c957 100644 --- a/retinaface.py +++ b/retinaface.py @@ -66,8 +66,7 @@ class RetinaFaceDetector(): options.execution_mode = onnxruntime.ExecutionMode.ORT_SEQUENTIAL options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL options.log_severity_level = 3 - providersList = onnxruntime.capi._pybind_state.get_available_providers() - self.session = onnxruntime.InferenceSession(model_path, sess_options=options, providers=providersList) + self.session = onnxruntime.InferenceSession(model_path, sess_options=options) self.res_w, self.res_h = res with open(json_path, "r") as prior_file: self.priorbox = np.array(json.loads(prior_file.read())) diff --git a/run.bat b/run.bat index ea2e030..50a004f 100644 --- a/run.bat +++ b/run.bat @@ -2,15 +2,12 @@ facetracker -l 1 -echo Make sure that nothing is accessing your camera before you proceed. set /p cameraNum=Select your camera from the list above and enter the corresponding number: - -facetracker -a %cameraNum% - -set /p dcaps=Select your camera mode or -1 for default settings: +set /p width=Select the width: +set /p height=Select the height: set /p fps=Select the FPS: -facetracker -c %cameraNum% -F %fps% -D %dcaps% -v 3 -P 1 --discard-after 0 --scan-every 0 --no-3d-adapt 1 --max-feature-updates 900 +facetracker -c %cameraNum% -W %width% -H %height% -F %fps% -v 3 -P 1 pause \ No newline at end of file diff --git a/similaritytransform.py b/similaritytransform.py deleted file mode 100644 index 4174787..0000000 --- a/similaritytransform.py +++ /dev/null @@ -1,1370 +0,0 @@ -# From scikit-image -import math -import numpy as np -import sys -import textwrap - -def get_bound_method_class(m): - """Return the class for a bound method. - - """ - return m.im_class if sys.version < '3' else m.__self__.__class__ - -def safe_as_int(val, atol=1e-3): - """ - Attempt to safely cast values to integer format. - - Parameters - ---------- - val : scalar or iterable of scalars - Number or container of numbers which are intended to be interpreted as - integers, e.g., for indexing purposes, but which may not carry integer - type. - atol : float - Absolute tolerance away from nearest integer to consider values in - ``val`` functionally integers. - - Returns - ------- - val_int : NumPy scalar or ndarray of dtype `np.int64` - Returns the input value(s) coerced to dtype `np.int64` assuming all - were within ``atol`` of the nearest integer. - - Notes - ----- - This operation calculates ``val`` modulo 1, which returns the mantissa of - all values. Then all mantissas greater than 0.5 are subtracted from one. - Finally, the absolute tolerance from zero is calculated. If it is less - than ``atol`` for all value(s) in ``val``, they are rounded and returned - in an integer array. Or, if ``val`` was a scalar, a NumPy scalar type is - returned. - - If any value(s) are outside the specified tolerance, an informative error - is raised. - - Examples - -------- - >>> safe_as_int(7.0) - 7 - - >>> safe_as_int([9, 4, 2.9999999999]) - array([9, 4, 3]) - - >>> safe_as_int(53.1) - Traceback (most recent call last): - ... - ValueError: Integer argument required but received 53.1, check inputs. - - >>> safe_as_int(53.01, atol=0.01) - 53 - - """ - mod = np.asarray(val) % 1 # Extract mantissa - - # Check for and subtract any mod values > 0.5 from 1 - if mod.ndim == 0: # Scalar input, cannot be indexed - if mod > 0.5: - mod = 1 - mod - else: # Iterable input, now ndarray - mod[mod > 0.5] = 1 - mod[mod > 0.5] # Test on each side of nearest int - - try: - np.testing.assert_allclose(mod, 0, atol=atol) - except AssertionError: - raise ValueError("Integer argument required but received " - "{0}, check inputs.".format(val)) - - return np.round(val).astype(np.int64) - -def _to_ndimage_mode(mode): - """Convert from `numpy.pad` mode name to the corresponding ndimage mode.""" - mode_translation_dict = dict(edge='nearest', symmetric='reflect', - reflect='mirror') - if mode in mode_translation_dict: - mode = mode_translation_dict[mode] - return mode - - -def _center_and_normalize_points(points): - """Center and normalize image points. - - The points are transformed in a two-step procedure that is expressed - as a transformation matrix. The matrix of the resulting points is usually - better conditioned than the matrix of the original points. - - Center the image points, such that the new coordinate system has its - origin at the centroid of the image points. - - Normalize the image points, such that the mean distance from the points - to the origin of the coordinate system is sqrt(2). - - Parameters - ---------- - points : (N, 2) array - The coordinates of the image points. - - Returns - ------- - matrix : (3, 3) array - The transformation matrix to obtain the new points. - new_points : (N, 2) array - The transformed image points. - - References - ---------- - .. [1] Hartley, Richard I. "In defense of the eight-point algorithm." - Pattern Analysis and Machine Intelligence, IEEE Transactions on 19.6 - (1997): 580-593. - - """ - - centroid = np.mean(points, axis=0) - - rms = math.sqrt(np.sum((points - centroid) ** 2) / points.shape[0]) - - norm_factor = math.sqrt(2) / rms - - matrix = np.array([[norm_factor, 0, -norm_factor * centroid[0]], - [0, norm_factor, -norm_factor * centroid[1]], - [0, 0, 1]]) - - pointsh = np.row_stack([points.T, np.ones((points.shape[0]),)]) - - new_pointsh = (matrix @ pointsh).T - - new_points = new_pointsh[:, :2] - new_points[:, 0] /= new_pointsh[:, 2] - new_points[:, 1] /= new_pointsh[:, 2] - - return matrix, new_points - - -def _umeyama(src, dst, estimate_scale): - """Estimate N-D similarity transformation with or without scaling. - - Parameters - ---------- - src : (M, N) array - Source coordinates. - dst : (M, N) array - Destination coordinates. - estimate_scale : bool - Whether to estimate scaling factor. - - Returns - ------- - T : (N + 1, N + 1) - The homogeneous similarity transformation matrix. The matrix contains - NaN values only if the problem is not well-conditioned. - - References - ---------- - .. [1] "Least-squares estimation of transformation parameters between two - point patterns", Shinji Umeyama, PAMI 1991, :DOI:`10.1109/34.88573` - - """ - - num = src.shape[0] - dim = src.shape[1] - - # Compute mean of src and dst. - src_mean = src.mean(axis=0) - dst_mean = dst.mean(axis=0) - - # Subtract mean from src and dst. - src_demean = src - src_mean - dst_demean = dst - dst_mean - - # Eq. (38). - A = dst_demean.T @ src_demean / num - - # Eq. (39). - d = np.ones((dim,), dtype=np.double) - if np.linalg.det(A) < 0: - d[dim - 1] = -1 - - T = np.eye(dim + 1, dtype=np.double) - - U, S, V = np.linalg.svd(A) - - # Eq. (40) and (43). - rank = np.linalg.matrix_rank(A) - if rank == 0: - return np.nan * T - elif rank == dim - 1: - if np.linalg.det(U) * np.linalg.det(V) > 0: - T[:dim, :dim] = U @ V - else: - s = d[dim - 1] - d[dim - 1] = -1 - T[:dim, :dim] = U @ np.diag(d) @ V - d[dim - 1] = s - else: - T[:dim, :dim] = U @ np.diag(d) @ V - - if estimate_scale: - # Eq. (41) and (42). - scale = 1.0 / src_demean.var(axis=0).sum() * (S @ d) - else: - scale = 1.0 - - T[:dim, dim] = dst_mean - scale * (T[:dim, :dim] @ src_mean.T) - T[:dim, :dim] *= scale - - return T - - -class GeometricTransform(object): - """Base class for geometric transformations. - - """ - def __call__(self, coords): - """Apply forward transformation. - - Parameters - ---------- - coords : (N, 2) array - Source coordinates. - - Returns - ------- - coords : (N, 2) array - Destination coordinates. - - """ - raise NotImplementedError() - - def inverse(self, coords): - """Apply inverse transformation. - - Parameters - ---------- - coords : (N, 2) array - Destination coordinates. - - Returns - ------- - coords : (N, 2) array - Source coordinates. - - """ - raise NotImplementedError() - - def residuals(self, src, dst): - """Determine residuals of transformed destination coordinates. - - For each transformed source coordinate the euclidean distance to the - respective destination coordinate is determined. - - Parameters - ---------- - src : (N, 2) array - Source coordinates. - dst : (N, 2) array - Destination coordinates. - - Returns - ------- - residuals : (N, ) array - Residual for coordinate. - - """ - return np.sqrt(np.sum((self(src) - dst)**2, axis=1)) - - def __add__(self, other): - """Combine this transformation with another. - - """ - raise NotImplementedError() - - -class FundamentalMatrixTransform(GeometricTransform): - """Fundamental matrix transformation. - - The fundamental matrix relates corresponding points between a pair of - uncalibrated images. The matrix transforms homogeneous image points in one - image to epipolar lines in the other image. - - The fundamental matrix is only defined for a pair of moving images. In the - case of pure rotation or planar scenes, the homography describes the - geometric relation between two images (`ProjectiveTransform`). If the - intrinsic calibration of the images is known, the essential matrix describes - the metric relation between the two images (`EssentialMatrixTransform`). - - References - ---------- - .. [1] Hartley, Richard, and Andrew Zisserman. Multiple view geometry in - computer vision. Cambridge university press, 2003. - - Parameters - ---------- - matrix : (3, 3) array, optional - Fundamental matrix. - - Attributes - ---------- - params : (3, 3) array - Fundamental matrix. - - """ - - def __init__(self, matrix=None): - if matrix is None: - # default to an identity transform - matrix = np.eye(3) - if matrix.shape != (3, 3): - raise ValueError("Invalid shape of transformation matrix") - self.params = matrix - - def __call__(self, coords): - """Apply forward transformation. - - Parameters - ---------- - coords : (N, 2) array - Source coordinates. - - Returns - ------- - coords : (N, 3) array - Epipolar lines in the destination image. - - """ - coords_homogeneous = np.column_stack([coords, np.ones(coords.shape[0])]) - return coords_homogeneous @ self.params.T - - def inverse(self, coords): - """Apply inverse transformation. - - Parameters - ---------- - coords : (N, 2) array - Destination coordinates. - - Returns - ------- - coords : (N, 3) array - Epipolar lines in the source image. - - """ - coords_homogeneous = np.column_stack([coords, np.ones(coords.shape[0])]) - return coords_homogeneous @ self.params - - def _setup_constraint_matrix(self, src, dst): - """Setup and solve the homogeneous epipolar constraint matrix:: - - dst' * F * src = 0. - - Parameters - ---------- - src : (N, 2) array - Source coordinates. - dst : (N, 2) array - Destination coordinates. - - Returns - ------- - F_normalized : (3, 3) array - The normalized solution to the homogeneous system. If the system - is not well-conditioned, this matrix contains NaNs. - src_matrix : (3, 3) array - The transformation matrix to obtain the normalized source - coordinates. - dst_matrix : (3, 3) array - The transformation matrix to obtain the normalized destination - coordinates. - - """ - if src.shape != dst.shape: - raise ValueError('src and dst shapes must be identical.') - if src.shape[0] < 8: - raise ValueError('src.shape[0] must be equal or larger than 8.') - - # Center and normalize image points for better numerical stability. - try: - src_matrix, src = _center_and_normalize_points(src) - dst_matrix, dst = _center_and_normalize_points(dst) - except ZeroDivisionError: - self.params = np.full((3, 3), np.nan) - return 3 * [np.full((3, 3), np.nan)] - - # Setup homogeneous linear equation as dst' * F * src = 0. - A = np.ones((src.shape[0], 9)) - A[:, :2] = src - A[:, :3] *= dst[:, 0, np.newaxis] - A[:, 3:5] = src - A[:, 3:6] *= dst[:, 1, np.newaxis] - A[:, 6:8] = src - - # Solve for the nullspace of the constraint matrix. - _, _, V = np.linalg.svd(A) - F_normalized = V[-1, :].reshape(3, 3) - - return F_normalized, src_matrix, dst_matrix - - def estimate(self, src, dst): - """Estimate fundamental matrix using 8-point algorithm. - - The 8-point algorithm requires at least 8 corresponding point pairs for - a well-conditioned solution, otherwise the over-determined solution is - estimated. - - Parameters - ---------- - src : (N, 2) array - Source coordinates. - dst : (N, 2) array - Destination coordinates. - - Returns - ------- - success : bool - True, if model estimation succeeds. - - """ - - F_normalized, src_matrix, dst_matrix = \ - self._setup_constraint_matrix(src, dst) - - # Enforcing the internal constraint that two singular values must be - # non-zero and one must be zero. - U, S, V = np.linalg.svd(F_normalized) - S[2] = 0 - F = U @ np.diag(S) @ V - - self.params = dst_matrix.T @ F @ src_matrix - - return True - - def residuals(self, src, dst): - """Compute the Sampson distance. - - The Sampson distance is the first approximation to the geometric error. - - Parameters - ---------- - src : (N, 2) array - Source coordinates. - dst : (N, 2) array - Destination coordinates. - - Returns - ------- - residuals : (N, ) array - Sampson distance. - - """ - src_homogeneous = np.column_stack([src, np.ones(src.shape[0])]) - dst_homogeneous = np.column_stack([dst, np.ones(dst.shape[0])]) - - F_src = self.params @ src_homogeneous.T - Ft_dst = self.params.T @ dst_homogeneous.T - - dst_F_src = np.sum(dst_homogeneous * F_src.T, axis=1) - - return np.abs(dst_F_src) / np.sqrt(F_src[0] ** 2 + F_src[1] ** 2 - + Ft_dst[0] ** 2 + Ft_dst[1] ** 2) - - -class EssentialMatrixTransform(FundamentalMatrixTransform): - """Essential matrix transformation. - - The essential matrix relates corresponding points between a pair of - calibrated images. The matrix transforms normalized, homogeneous image - points in one image to epipolar lines in the other image. - - The essential matrix is only defined for a pair of moving images capturing a - non-planar scene. In the case of pure rotation or planar scenes, the - homography describes the geometric relation between two images - (`ProjectiveTransform`). If the intrinsic calibration of the images is - unknown, the fundamental matrix describes the projective relation between - the two images (`FundamentalMatrixTransform`). - - References - ---------- - .. [1] Hartley, Richard, and Andrew Zisserman. Multiple view geometry in - computer vision. Cambridge university press, 2003. - - Parameters - ---------- - rotation : (3, 3) array, optional - Rotation matrix of the relative camera motion. - translation : (3, 1) array, optional - Translation vector of the relative camera motion. The vector must - have unit length. - matrix : (3, 3) array, optional - Essential matrix. - - Attributes - ---------- - params : (3, 3) array - Essential matrix. - - """ - - def __init__(self, rotation=None, translation=None, matrix=None): - if rotation is not None: - if translation is None: - raise ValueError("Both rotation and translation required") - if rotation.shape != (3, 3): - raise ValueError("Invalid shape of rotation matrix") - if abs(np.linalg.det(rotation) - 1) > 1e-6: - raise ValueError("Rotation matrix must have unit determinant") - if translation.size != 3: - raise ValueError("Invalid shape of translation vector") - if abs(np.linalg.norm(translation) - 1) > 1e-6: - raise ValueError("Translation vector must have unit length") - # Matrix representation of the cross product for t. - t_x = np.array([0, -translation[2], translation[1], - translation[2], 0, -translation[0], - -translation[1], translation[0], 0]).reshape(3, 3) - self.params = t_x @ rotation - elif matrix is not None: - if matrix.shape != (3, 3): - raise ValueError("Invalid shape of transformation matrix") - self.params = matrix - else: - # default to an identity transform - self.params = np.eye(3) - - def estimate(self, src, dst): - """Estimate essential matrix using 8-point algorithm. - - The 8-point algorithm requires at least 8 corresponding point pairs for - a well-conditioned solution, otherwise the over-determined solution is - estimated. - - Parameters - ---------- - src : (N, 2) array - Source coordinates. - dst : (N, 2) array - Destination coordinates. - - Returns - ------- - success : bool - True, if model estimation succeeds. - - """ - - E_normalized, src_matrix, dst_matrix = \ - self._setup_constraint_matrix(src, dst) - - # Enforcing the internal constraint that two singular values must be - # equal and one must be zero. - U, S, V = np.linalg.svd(E_normalized) - S[0] = (S[0] + S[1]) / 2.0 - S[1] = S[0] - S[2] = 0 - E = U @ np.diag(S) @ V - - self.params = dst_matrix.T @ E @ src_matrix - - return True - - -class ProjectiveTransform(GeometricTransform): - r"""Projective transformation. - - Apply a projective transformation (homography) on coordinates. - - For each homogeneous coordinate :math:`\mathbf{x} = [x, y, 1]^T`, its - target position is calculated by multiplying with the given matrix, - :math:`H`, to give :math:`H \mathbf{x}`:: - - [[a0 a1 a2] - [b0 b1 b2] - [c0 c1 1 ]]. - - E.g., to rotate by theta degrees clockwise, the matrix should be:: - - [[cos(theta) -sin(theta) 0] - [sin(theta) cos(theta) 0] - [0 0 1]] - - or, to translate x by 10 and y by 20:: - - [[1 0 10] - [0 1 20] - [0 0 1 ]]. - - Parameters - ---------- - matrix : (3, 3) array, optional - Homogeneous transformation matrix. - - Attributes - ---------- - params : (3, 3) array - Homogeneous transformation matrix. - - """ - - _coeffs = range(8) - - def __init__(self, matrix=None): - if matrix is None: - # default to an identity transform - matrix = np.eye(3) - if matrix.shape != (3, 3): - raise ValueError("invalid shape of transformation matrix") - self.params = matrix - - @property - def _inv_matrix(self): - return np.linalg.inv(self.params) - - def _apply_mat(self, coords, matrix): - coords = np.array(coords, copy=False, ndmin=2) - - x, y = np.transpose(coords) - src = np.vstack((x, y, np.ones_like(x))) - dst = src.T @ matrix.T - - # below, we will divide by the last dimension of the homogeneous - # coordinate matrix. In order to avoid division by zero, - # we replace exact zeros in this column with a very small number. - dst[dst[:, 2] == 0, 2] = np.finfo(float).eps - # rescale to homogeneous coordinates - dst[:, :2] /= dst[:, 2:3] - - return dst[:, :2] - - def __call__(self, coords): - """Apply forward transformation. - - Parameters - ---------- - coords : (N, 2) array - Source coordinates. - - Returns - ------- - coords : (N, 2) array - Destination coordinates. - - """ - return self._apply_mat(coords, self.params) - - def inverse(self, coords): - """Apply inverse transformation. - - Parameters - ---------- - coords : (N, 2) array - Destination coordinates. - - Returns - ------- - coords : (N, 2) array - Source coordinates. - - """ - return self._apply_mat(coords, self._inv_matrix) - - def estimate(self, src, dst): - """Estimate the transformation from a set of corresponding points. - - You can determine the over-, well- and under-determined parameters - with the total least-squares method. - - Number of source and destination coordinates must match. - - The transformation is defined as:: - - X = (a0*x + a1*y + a2) / (c0*x + c1*y + 1) - Y = (b0*x + b1*y + b2) / (c0*x + c1*y + 1) - - These equations can be transformed to the following form:: - - 0 = a0*x + a1*y + a2 - c0*x*X - c1*y*X - X - 0 = b0*x + b1*y + b2 - c0*x*Y - c1*y*Y - Y - - which exist for each set of corresponding points, so we have a set of - N * 2 equations. The coefficients appear linearly so we can write - A x = 0, where:: - - A = [[x y 1 0 0 0 -x*X -y*X -X] - [0 0 0 x y 1 -x*Y -y*Y -Y] - ... - ... - ] - x.T = [a0 a1 a2 b0 b1 b2 c0 c1 c3] - - In case of total least-squares the solution of this homogeneous system - of equations is the right singular vector of A which corresponds to the - smallest singular value normed by the coefficient c3. - - In case of the affine transformation the coefficients c0 and c1 are 0. - Thus the system of equations is:: - - A = [[x y 1 0 0 0 -X] - [0 0 0 x y 1 -Y] - ... - ... - ] - x.T = [a0 a1 a2 b0 b1 b2 c3] - - Parameters - ---------- - src : (N, 2) array - Source coordinates. - dst : (N, 2) array - Destination coordinates. - - Returns - ------- - success : bool - True, if model estimation succeeds. - - """ - - try: - src_matrix, src = _center_and_normalize_points(src) - dst_matrix, dst = _center_and_normalize_points(dst) - except ZeroDivisionError: - self.params = np.nan * np.empty((3, 3)) - return False - - xs = src[:, 0] - ys = src[:, 1] - xd = dst[:, 0] - yd = dst[:, 1] - rows = src.shape[0] - - # params: a0, a1, a2, b0, b1, b2, c0, c1 - A = np.zeros((rows * 2, 9)) - A[:rows, 0] = xs - A[:rows, 1] = ys - A[:rows, 2] = 1 - A[:rows, 6] = - xd * xs - A[:rows, 7] = - xd * ys - A[rows:, 3] = xs - A[rows:, 4] = ys - A[rows:, 5] = 1 - A[rows:, 6] = - yd * xs - A[rows:, 7] = - yd * ys - A[:rows, 8] = xd - A[rows:, 8] = yd - - # Select relevant columns, depending on params - A = A[:, list(self._coeffs) + [8]] - - _, _, V = np.linalg.svd(A) - # if the last element of the vector corresponding to the smallest - # singular value is close to zero, this implies a degenerate case - # because it is a rank-defective transform, which would map points - # to a line rather than a plane. - if np.isclose(V[-1, -1], 0): - return False - - H = np.zeros((3, 3)) - # solution is right singular vector that corresponds to smallest - # singular value - H.flat[list(self._coeffs) + [8]] = - V[-1, :-1] / V[-1, -1] - H[2, 2] = 1 - - # De-center and de-normalize - H = np.linalg.inv(dst_matrix) @ H @ src_matrix - - self.params = H - - return True - - def __add__(self, other): - """Combine this transformation with another. - - """ - if isinstance(other, ProjectiveTransform): - # combination of the same types result in a transformation of this - # type again, otherwise use general projective transformation - if type(self) == type(other): - tform = self.__class__ - else: - tform = ProjectiveTransform - return tform(other.params @ self.params) - elif (hasattr(other, '__name__') - and other.__name__ == 'inverse' - and hasattr(get_bound_method_class(other), '_inv_matrix')): - return ProjectiveTransform(other.__self__._inv_matrix @ self.params) - else: - raise TypeError("Cannot combine transformations of differing " - "types.") - - def __nice__(self): - """common 'paramstr' used by __str__ and __repr__""" - npstring = np.array2string(self.params, separator=', ') - paramstr = 'matrix=\n' + textwrap.indent(npstring, ' ') - return paramstr - - def __repr__(self): - """Add standard repr formatting around a __nice__ string""" - paramstr = self.__nice__() - classname = self.__class__.__name__ - classstr = classname - return '<{}({}) at {}>'.format(classstr, paramstr, hex(id(self))) - - def __str__(self): - """Add standard str formatting around a __nice__ string""" - paramstr = self.__nice__() - classname = self.__class__.__name__ - classstr = classname - return '<{}({})>'.format(classstr, paramstr) - - -class AffineTransform(ProjectiveTransform): - """2D affine transformation. - - Has the following form:: - - X = a0*x + a1*y + a2 = - = sx*x*cos(rotation) - sy*y*sin(rotation + shear) + a2 - - Y = b0*x + b1*y + b2 = - = sx*x*sin(rotation) + sy*y*cos(rotation + shear) + b2 - - where ``sx`` and ``sy`` are scale factors in the x and y directions, - and the homogeneous transformation matrix is:: - - [[a0 a1 a2] - [b0 b1 b2] - [0 0 1]] - - Parameters - ---------- - matrix : (3, 3) array, optional - Homogeneous transformation matrix. - scale : {s as float or (sx, sy) as array, list or tuple}, optional - Scale factor(s). If a single value, it will be assigned to both - sx and sy. - - .. versionadded:: 0.17 - Added support for supplying a single scalar value. - rotation : float, optional - Rotation angle in counter-clockwise direction as radians. - shear : float, optional - Shear angle in counter-clockwise direction as radians. - translation : (tx, ty) as array, list or tuple, optional - Translation parameters. - - Attributes - ---------- - params : (3, 3) array - Homogeneous transformation matrix. - - """ - - _coeffs = range(6) - - def __init__(self, matrix=None, scale=None, rotation=None, shear=None, - translation=None): - params = any(param is not None - for param in (scale, rotation, shear, translation)) - - if params and matrix is not None: - raise ValueError("You cannot specify the transformation matrix and" - " the implicit parameters at the same time.") - elif matrix is not None: - if matrix.shape != (3, 3): - raise ValueError("Invalid shape of transformation matrix.") - self.params = matrix - elif params: - if scale is None: - scale = (1, 1) - if rotation is None: - rotation = 0 - if shear is None: - shear = 0 - if translation is None: - translation = (0, 0) - - if np.isscalar(scale): - sx = sy = scale - else: - sx, sy = scale - - self.params = np.array([ - [sx * math.cos(rotation), -sy * math.sin(rotation + shear), 0], - [sx * math.sin(rotation), sy * math.cos(rotation + shear), 0], - [ 0, 0, 1] - ]) - self.params[0:2, 2] = translation - else: - # default to an identity transform - self.params = np.eye(3) - - @property - def scale(self): - sx = math.sqrt(self.params[0, 0] ** 2 + self.params[1, 0] ** 2) - sy = math.sqrt(self.params[0, 1] ** 2 + self.params[1, 1] ** 2) - return sx, sy - - @property - def rotation(self): - return math.atan2(self.params[1, 0], self.params[0, 0]) - - @property - def shear(self): - beta = math.atan2(- self.params[0, 1], self.params[1, 1]) - return beta - self.rotation - - @property - def translation(self): - return self.params[0:2, 2] - - - - - -class EuclideanTransform(ProjectiveTransform): - """2D Euclidean transformation. - - Has the following form:: - - X = a0 * x - b0 * y + a1 = - = x * cos(rotation) - y * sin(rotation) + a1 - - Y = b0 * x + a0 * y + b1 = - = x * sin(rotation) + y * cos(rotation) + b1 - - where the homogeneous transformation matrix is:: - - [[a0 b0 a1] - [b0 a0 b1] - [0 0 1]] - - The Euclidean transformation is a rigid transformation with rotation and - translation parameters. The similarity transformation extends the Euclidean - transformation with a single scaling factor. - - Parameters - ---------- - matrix : (3, 3) array, optional - Homogeneous transformation matrix. - rotation : float, optional - Rotation angle in counter-clockwise direction as radians. - translation : (tx, ty) as array, list or tuple, optional - x, y translation parameters. - - Attributes - ---------- - params : (3, 3) array - Homogeneous transformation matrix. - - """ - - def __init__(self, matrix=None, rotation=None, translation=None): - params = any(param is not None - for param in (rotation, translation)) - - if params and matrix is not None: - raise ValueError("You cannot specify the transformation matrix and" - " the implicit parameters at the same time.") - elif matrix is not None: - if matrix.shape != (3, 3): - raise ValueError("Invalid shape of transformation matrix.") - self.params = matrix - elif params: - if rotation is None: - rotation = 0 - if translation is None: - translation = (0, 0) - - self.params = np.array([ - [math.cos(rotation), - math.sin(rotation), 0], - [math.sin(rotation), math.cos(rotation), 0], - [ 0, 0, 1] - ]) - self.params[0:2, 2] = translation - else: - # default to an identity transform - self.params = np.eye(3) - - def estimate(self, src, dst): - """Estimate the transformation from a set of corresponding points. - - You can determine the over-, well- and under-determined parameters - with the total least-squares method. - - Number of source and destination coordinates must match. - - Parameters - ---------- - src : (N, 2) array - Source coordinates. - dst : (N, 2) array - Destination coordinates. - - Returns - ------- - success : bool - True, if model estimation succeeds. - - """ - - self.params = _umeyama(src, dst, False) - - return True - - @property - def rotation(self): - return math.atan2(self.params[1, 0], self.params[1, 1]) - - @property - def translation(self): - return self.params[0:2, 2] - - -class SimilarityTransform(EuclideanTransform): - """2D similarity transformation. - - Has the following form:: - - X = a0 * x - b0 * y + a1 = - = s * x * cos(rotation) - s * y * sin(rotation) + a1 - - Y = b0 * x + a0 * y + b1 = - = s * x * sin(rotation) + s * y * cos(rotation) + b1 - - where ``s`` is a scale factor and the homogeneous transformation matrix is:: - - [[a0 b0 a1] - [b0 a0 b1] - [0 0 1]] - - The similarity transformation extends the Euclidean transformation with a - single scaling factor in addition to the rotation and translation - parameters. - - Parameters - ---------- - matrix : (3, 3) array, optional - Homogeneous transformation matrix. - scale : float, optional - Scale factor. - rotation : float, optional - Rotation angle in counter-clockwise direction as radians. - translation : (tx, ty) as array, list or tuple, optional - x, y translation parameters. - - Attributes - ---------- - params : (3, 3) array - Homogeneous transformation matrix. - - """ - - def __init__(self, matrix=None, scale=None, rotation=None, - translation=None): - params = any(param is not None - for param in (scale, rotation, translation)) - - if params and matrix is not None: - raise ValueError("You cannot specify the transformation matrix and" - " the implicit parameters at the same time.") - elif matrix is not None: - if matrix.shape != (3, 3): - raise ValueError("Invalid shape of transformation matrix.") - self.params = matrix - elif params: - if scale is None: - scale = 1 - if rotation is None: - rotation = 0 - if translation is None: - translation = (0, 0) - - self.params = np.array([ - [math.cos(rotation), - math.sin(rotation), 0], - [math.sin(rotation), math.cos(rotation), 0], - [ 0, 0, 1] - ]) - self.params[0:2, 0:2] *= scale - self.params[0:2, 2] = translation - else: - # default to an identity transform - self.params = np.eye(3) - - def estimate(self, src, dst): - """Estimate the transformation from a set of corresponding points. - - You can determine the over-, well- and under-determined parameters - with the total least-squares method. - - Number of source and destination coordinates must match. - - Parameters - ---------- - src : (N, 2) array - Source coordinates. - dst : (N, 2) array - Destination coordinates. - - Returns - ------- - success : bool - True, if model estimation succeeds. - - """ - - self.params = _umeyama(src, dst, True) - - return True - - @property - def scale(self): - # det = scale**(# of dimensions), therefore scale = det**(1/2) - return np.sqrt(np.linalg.det(self.params)) - - -class PolynomialTransform(GeometricTransform): - """2D polynomial transformation. - - Has the following form:: - - X = sum[j=0:order]( sum[i=0:j]( a_ji * x**(j - i) * y**i )) - Y = sum[j=0:order]( sum[i=0:j]( b_ji * x**(j - i) * y**i )) - - Parameters - ---------- - params : (2, N) array, optional - Polynomial coefficients where `N * 2 = (order + 1) * (order + 2)`. So, - a_ji is defined in `params[0, :]` and b_ji in `params[1, :]`. - - Attributes - ---------- - params : (2, N) array - Polynomial coefficients where `N * 2 = (order + 1) * (order + 2)`. So, - a_ji is defined in `params[0, :]` and b_ji in `params[1, :]`. - - """ - - def __init__(self, params=None): - if params is None: - # default to transformation which preserves original coordinates - params = np.array([[0, 1, 0], [0, 0, 1]]) - if params.shape[0] != 2: - raise ValueError("invalid shape of transformation parameters") - self.params = params - - def estimate(self, src, dst, order=2): - """Estimate the transformation from a set of corresponding points. - - You can determine the over-, well- and under-determined parameters - with the total least-squares method. - - Number of source and destination coordinates must match. - - The transformation is defined as:: - - X = sum[j=0:order]( sum[i=0:j]( a_ji * x**(j - i) * y**i )) - Y = sum[j=0:order]( sum[i=0:j]( b_ji * x**(j - i) * y**i )) - - These equations can be transformed to the following form:: - - 0 = sum[j=0:order]( sum[i=0:j]( a_ji * x**(j - i) * y**i )) - X - 0 = sum[j=0:order]( sum[i=0:j]( b_ji * x**(j - i) * y**i )) - Y - - which exist for each set of corresponding points, so we have a set of - N * 2 equations. The coefficients appear linearly so we can write - A x = 0, where:: - - A = [[1 x y x**2 x*y y**2 ... 0 ... 0 -X] - [0 ... 0 1 x y x**2 x*y y**2 -Y] - ... - ... - ] - x.T = [a00 a10 a11 a20 a21 a22 ... ann - b00 b10 b11 b20 b21 b22 ... bnn c3] - - In case of total least-squares the solution of this homogeneous system - of equations is the right singular vector of A which corresponds to the - smallest singular value normed by the coefficient c3. - - Parameters - ---------- - src : (N, 2) array - Source coordinates. - dst : (N, 2) array - Destination coordinates. - order : int, optional - Polynomial order (number of coefficients is order + 1). - - Returns - ------- - success : bool - True, if model estimation succeeds. - - """ - xs = src[:, 0] - ys = src[:, 1] - xd = dst[:, 0] - yd = dst[:, 1] - rows = src.shape[0] - - # number of unknown polynomial coefficients - order = safe_as_int(order) - u = (order + 1) * (order + 2) - - A = np.zeros((rows * 2, u + 1)) - pidx = 0 - for j in range(order + 1): - for i in range(j + 1): - A[:rows, pidx] = xs ** (j - i) * ys ** i - A[rows:, pidx + u // 2] = xs ** (j - i) * ys ** i - pidx += 1 - - A[:rows, -1] = xd - A[rows:, -1] = yd - - _, _, V = np.linalg.svd(A) - - # solution is right singular vector that corresponds to smallest - # singular value - params = - V[-1, :-1] / V[-1, -1] - - self.params = params.reshape((2, u // 2)) - - return True - - def __call__(self, coords): - """Apply forward transformation. - - Parameters - ---------- - coords : (N, 2) array - source coordinates - - Returns - ------- - coords : (N, 2) array - Transformed coordinates. - - """ - x = coords[:, 0] - y = coords[:, 1] - u = len(self.params.ravel()) - # number of coefficients -> u = (order + 1) * (order + 2) - order = int((- 3 + math.sqrt(9 - 4 * (2 - u))) / 2) - dst = np.zeros(coords.shape) - - pidx = 0 - for j in range(order + 1): - for i in range(j + 1): - dst[:, 0] += self.params[0, pidx] * x ** (j - i) * y ** i - dst[:, 1] += self.params[1, pidx] * x ** (j - i) * y ** i - pidx += 1 - - return dst - - def inverse(self, coords): - raise Exception( - 'There is no explicit way to do the inverse polynomial ' - 'transformation. Instead, estimate the inverse transformation ' - 'parameters by exchanging source and destination coordinates,' - 'then apply the forward transformation.') - - -TRANSFORMS = { - 'euclidean': EuclideanTransform, - 'similarity': SimilarityTransform, - 'affine': AffineTransform, - 'projective': ProjectiveTransform, - 'fundamental': FundamentalMatrixTransform, - 'essential': EssentialMatrixTransform, - 'polynomial': PolynomialTransform, -} - - -def estimate_transform(ttype, src, dst, **kwargs): - """Estimate 2D geometric transformation parameters. - - You can determine the over-, well- and under-determined parameters - with the total least-squares method. - - Number of source and destination coordinates must match. - - Parameters - ---------- - ttype : {'euclidean', similarity', 'affine', 'piecewise-affine', \ - 'projective', 'polynomial'} - Type of transform. - kwargs : array or int - Function parameters (src, dst, n, angle):: - - NAME / TTYPE FUNCTION PARAMETERS - 'euclidean' `src, `dst` - 'similarity' `src, `dst` - 'affine' `src, `dst` - 'piecewise-affine' `src, `dst` - 'projective' `src, `dst` - 'polynomial' `src, `dst`, `order` (polynomial order, - default order is 2) - - Also see examples below. - - Returns - ------- - tform : :class:`GeometricTransform` - Transform object containing the transformation parameters and providing - access to forward and inverse transformation functions. - - Examples - -------- - >>> import numpy as np - >>> from skimage import transform - - >>> # estimate transformation parameters - >>> src = np.array([0, 0, 10, 10]).reshape((2, 2)) - >>> dst = np.array([12, 14, 1, -20]).reshape((2, 2)) - - >>> tform = transform.estimate_transform('similarity', src, dst) - - >>> np.allclose(tform.inverse(tform(src)), src) - True - - >>> # warp image using the estimated transformation - >>> from skimage import data - >>> image = data.camera() - - >>> warp(image, inverse_map=tform.inverse) # doctest: +SKIP - - >>> # create transformation with explicit parameters - >>> tform2 = transform.SimilarityTransform(scale=1.1, rotation=1, - ... translation=(10, 20)) - - >>> # unite transformations, applied in order from left to right - >>> tform3 = tform + tform2 - >>> np.allclose(tform3(src), tform2(tform(src))) - True - - """ - ttype = ttype.lower() - if ttype not in TRANSFORMS: - raise ValueError('the transformation type \'%s\' is not' - 'implemented' % ttype) - - tform = TRANSFORMS[ttype]() - tform.estimate(src, dst, **kwargs) - - return tform - - -def matrix_transform(coords, matrix): - """Apply 2D matrix transform. - - Parameters - ---------- - coords : (N, 2) array - x, y coordinates to transform - matrix : (3, 3) array - Homogeneous transformation matrix. - - Returns - ------- - coords : (N, 2) array - Transformed coordinates. - - """ - return ProjectiveTransform(matrix)(coords) diff --git a/tracker.py b/tracker.py index 26f8305..f8ef138 100644 --- a/tracker.py +++ b/tracker.py @@ -7,7 +7,6 @@ import time import queue import threading import copy -from similaritytransform import SimilarityTransform from retinaface import RetinaFaceDetector from remedian import remedian @@ -50,7 +49,7 @@ def compensate(p1, p2): def rotate_image(image, a, center): (h, w) = image.shape[:2] a = np.rad2deg(a) - M = cv2.getRotationMatrix2D((float(center[0]), float(center[1])), a, 1.0) + M = cv2.getRotationMatrix2D((center[0], center[1]), a, 1.0) rotated = cv2.warpAffine(image, M, (w, h)) return rotated @@ -111,10 +110,6 @@ def logit(p, factor=16.0): p = p/(1-p) return float(np.log(p)) / float(factor) -def logit_arr(p, factor=16.0): - p = np.clip(p, 0.0000001, 0.9999999) - return np.log(p / (1 - p)) / float(factor) - def matrix_to_quaternion(m): t = 0.0 q = [0.0, 0.0, 0, 0.0] @@ -139,16 +134,13 @@ def worker_thread(session, frame, input, crop_info, queue, input_name, idx, trac output = session.run([], {input_name: input})[0] conf, lms = tracker.landmarks(output[0], crop_info) if conf > tracker.threshold: - try: - eye_state = tracker.get_eye_state(frame, lms) - except: - eye_state = [(1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0)] + eye_state = tracker.get_eye_state(frame, lms, single=True) queue.put((session, conf, (lms, eye_state), crop_info, idx)) else: queue.put((session,)) class Feature(): - def __init__(self, threshold=0.15, alpha=0.2, hard_factor=0.15, decay=0.001, max_feature_updates=0): + def __init__(self, threshold=0.15, alpha=0.2, hard_factor=0.15, decay=0.001): self.median = remedian() self.min = None self.max = None @@ -159,62 +151,44 @@ class Feature(): self.hard_factor = hard_factor self.decay = decay self.last = 0 - self.current_median = 0 - self.update_count = 0 - self.max_feature_updates = max_feature_updates - self.first_seen = -1 - self.updating = True - def update(self, x, now=0): - if self.max_feature_updates > 0: - if self.first_seen == -1: - self.first_seen = now; - new = self.update_state(x, now=now) + def update(self, x): + new = self.update_state(x) filtered = self.last * self.alpha + new * (1 - self.alpha) self.last = filtered return filtered - def update_state(self, x, now=0): - updating = self.updating and (self.max_feature_updates == 0 or now - self.first_seen < self.max_feature_updates) - if updating: - self.median + x - self.current_median = self.median.median() - else: - self.updating = False - median = self.current_median + def update_state(self, x): + self.median + x + median = self.median.median() if self.min is None: if x < median and (median - x) / median > self.threshold: - if updating: - self.min = x - self.hard_min = self.min + self.hard_factor * (median - self.min) + self.min = x + self.hard_min = self.min + self.hard_factor * (median - self.min) return -1 return 0 else: if x < self.min: - if updating: - self.min = x - self.hard_min = self.min + self.hard_factor * (median - self.min) + self.min = x + self.hard_min = self.min + self.hard_factor * (median - self.min) return -1 if self.max is None: if x > median and (x - median) / median > self.threshold: - if updating: - self.max = x - self.hard_max = self.max - self.hard_factor * (self.max - median) + self.max = x + self.hard_max = self.max - self.hard_factor * (self.max - median) return 1 return 0 else: if x > self.max: - if updating: - self.max = x - self.hard_max = self.max - self.hard_factor * (self.max - median) + self.max = x + self.hard_max = self.max - self.hard_factor * (self.max - median) return 1 - if updating: - if self.min < self.hard_min: - self.min = self.hard_min * self.decay + self.min * (1 - self.decay) - if self.max > self.hard_max: - self.max = self.hard_max * self.decay + self.max * (1 - self.decay) + if self.min < self.hard_min: + self.min = self.hard_min * self.decay + self.min * (1 - self.decay) + if self.max > self.hard_max: + self.max = self.hard_max * self.decay + self.max * (1 - self.decay) if x < median: return - (1 - (x - self.min) / (median - self.min)) @@ -224,21 +198,21 @@ class Feature(): return 0 class FeatureExtractor(): - def __init__(self, max_feature_updates=0): - self.eye_l = Feature(max_feature_updates=max_feature_updates) - self.eye_r = Feature(max_feature_updates=max_feature_updates) - self.eyebrow_updown_l = Feature(max_feature_updates=max_feature_updates) - self.eyebrow_updown_r = Feature(max_feature_updates=max_feature_updates) - self.eyebrow_quirk_l = Feature(threshold=0.05, max_feature_updates=max_feature_updates) - self.eyebrow_quirk_r = Feature(threshold=0.05, max_feature_updates=max_feature_updates) - self.eyebrow_steepness_l = Feature(threshold=0.05, max_feature_updates=max_feature_updates) - self.eyebrow_steepness_r = Feature(threshold=0.05, max_feature_updates=max_feature_updates) - self.mouth_corner_updown_l = Feature(max_feature_updates=max_feature_updates) - self.mouth_corner_updown_r = Feature(max_feature_updates=max_feature_updates) - self.mouth_corner_inout_l = Feature(threshold=0.02, max_feature_updates=max_feature_updates) - self.mouth_corner_inout_r = Feature(threshold=0.02, max_feature_updates=max_feature_updates) - self.mouth_open = Feature(max_feature_updates=max_feature_updates) - self.mouth_wide = Feature(threshold=0.02, max_feature_updates=max_feature_updates) + def __init__(self): + self.eye_l = Feature() + self.eye_r = Feature() + self.eyebrow_updown_l = Feature() + self.eyebrow_updown_r = Feature() + self.eyebrow_quirk_l = Feature(threshold=0.05) + self.eyebrow_quirk_r = Feature(threshold=0.05) + self.eyebrow_steepness_l = Feature(threshold=0.05) + self.eyebrow_steepness_r = Feature(threshold=0.05) + self.mouth_corner_updown_l = Feature() + self.mouth_corner_updown_r = Feature() + self.mouth_corner_inout_l = Feature(threshold=0.02) + self.mouth_corner_inout_r = Feature(threshold=0.02) + self.mouth_open = Feature() + self.mouth_wide = Feature(threshold=0.02) def align_points(self, a, b, pts): a = tuple(a) @@ -255,71 +229,56 @@ class FeatureExtractor(): aligned_pts.append(np.array(rotate(a, pt, alpha))) return alpha, np.array(aligned_pts) - def update(self, pts, full=True): + def update(self, pts): features = {} - now = time.perf_counter() norm_distance_x = np.mean([pts[0, 0] - pts[16, 0], pts[1, 0] - pts[15, 0]]) norm_distance_y = np.mean([pts[27, 1] - pts[28, 1], pts[28, 1] - pts[29, 1], pts[29, 1] - pts[30, 1]]) a1, f_pts = self.align_points(pts[42], pts[45], pts[[43, 44, 47, 46]]) - f = abs((np.mean([f_pts[0,1], f_pts[1,1]]) - np.mean([f_pts[2,1], f_pts[3,1]])) / norm_distance_y) - features["eye_l"] = self.eye_l.update(f, now) + f = np.clip((np.mean([f_pts[0,1], f_pts[1,1]]) - np.mean([f_pts[2,1], f_pts[3,1]])) / norm_distance_y, 0, None) + features["eye_l"] = self.eye_l.update(f) a2, f_pts = self.align_points(pts[36], pts[39], pts[[37, 38, 41, 40]]) - f = abs((np.mean([f_pts[0,1], f_pts[1,1]]) - np.mean([f_pts[2,1], f_pts[3,1]])) / norm_distance_y) - features["eye_r"] = self.eye_r.update(f, now) + f = np.clip((np.mean([f_pts[0,1], f_pts[1,1]]) - np.mean([f_pts[2,1], f_pts[3,1]])) / norm_distance_y, 0, None) + features["eye_r"] = self.eye_r.update(f) - if full: - a3, _ = self.align_points(pts[0], pts[16], []) - a4, _ = self.align_points(pts[31], pts[35], []) - norm_angle = np.mean(list(map(np.rad2deg, [a1, a2, a3, a4]))) - - a, f_pts = self.align_points(pts[22], pts[26], pts[[22, 23, 24, 25, 26]]) - features["eyebrow_steepness_l"] = self.eyebrow_steepness_l.update(-np.rad2deg(a) - norm_angle, now) - f = np.max(np.abs(np.array(f_pts[1:4]) - f_pts[0, 1])) / norm_distance_y - features["eyebrow_quirk_l"] = self.eyebrow_quirk_l.update(f, now) - - a, f_pts = self.align_points(pts[17], pts[21], pts[[17, 18, 19, 20, 21]]) - features["eyebrow_steepness_r"] = self.eyebrow_steepness_r.update(np.rad2deg(a) - norm_angle, now) - f = np.max(np.abs(np.array(f_pts[1:4]) - f_pts[0, 1])) / norm_distance_y - features["eyebrow_quirk_r"] = self.eyebrow_quirk_r.update(f, now) - else: - features["eyebrow_steepness_l"] = 0. - features["eyebrow_steepness_r"] = 0. - features["eyebrow_quirk_l"] = 0. - features["eyebrow_quirk_r"] = 0. + a3, _ = self.align_points(pts[0], pts[16], []) + a4, _ = self.align_points(pts[31], pts[35], []) + norm_angle = np.mean(list(map(np.rad2deg, [a1, a2, a3, a4]))) + a, f_pts = self.align_points(pts[22], pts[26], pts[[22, 23, 24, 25, 26]]) + features["eyebrow_steepness_l"] = self.eyebrow_steepness_l.update(-np.rad2deg(a) - norm_angle) f = (np.mean([pts[22, 1], pts[26, 1]]) - pts[27, 1]) / norm_distance_y - features["eyebrow_updown_l"] = self.eyebrow_updown_l.update(f, now) + features["eyebrow_updown_l"] = self.eyebrow_updown_l.update(f) + f = np.max(np.abs(np.array(f_pts[1:4]) - f_pts[0, 1])) / norm_distance_y + features["eyebrow_quirk_l"] = self.eyebrow_quirk_l.update(f) + a, f_pts = self.align_points(pts[17], pts[21], pts[[17, 18, 19, 20, 21]]) + features["eyebrow_steepness_r"] = self.eyebrow_steepness_r.update(np.rad2deg(a) - norm_angle) f = (np.mean([pts[17, 1], pts[21, 1]]) - pts[27, 1]) / norm_distance_y - features["eyebrow_updown_r"] = self.eyebrow_updown_r.update(f, now) + features["eyebrow_updown_r"] = self.eyebrow_updown_r.update(f) + f = np.max(np.abs(np.array(f_pts[1:4]) - f_pts[0, 1])) / norm_distance_y + features["eyebrow_quirk_r"] = self.eyebrow_quirk_r.update(f) upper_mouth_line = np.mean([pts[49, 1], pts[50, 1], pts[51, 1]]) center_line = np.mean([pts[50, 0], pts[60, 0], pts[27, 0], pts[30, 0], pts[64, 0], pts[55, 0]]) f = (upper_mouth_line - pts[62, 1]) / norm_distance_y - features["mouth_corner_updown_l"] = self.mouth_corner_updown_l.update(f, now) - if full: - f = abs(center_line - pts[62, 0]) / norm_distance_x - features["mouth_corner_inout_l"] = self.mouth_corner_inout_l.update(f, now) - else: - features["mouth_corner_inout_l"] = 0. + features["mouth_corner_updown_l"] = self.mouth_corner_updown_l.update(f) + f = abs(center_line - pts[62, 0]) / norm_distance_x + features["mouth_corner_inout_l"] = self.mouth_corner_inout_l.update(f) f = (upper_mouth_line - pts[58, 1]) / norm_distance_y - features["mouth_corner_updown_r"] = self.mouth_corner_updown_r.update(f, now) - if full: - f = abs(center_line - pts[58, 0]) / norm_distance_x - features["mouth_corner_inout_r"] = self.mouth_corner_inout_r.update(f, now) - else: - features["mouth_corner_inout_r"] = 0. + features["mouth_corner_updown_r"] = self.mouth_corner_updown_r.update(f) + f = abs(center_line - pts[58, 0]) / norm_distance_x + features["mouth_corner_inout_r"] = self.mouth_corner_inout_r.update(f) - f = abs(np.mean(pts[[59,60,61], 1], axis=0) - np.mean(pts[[63,64,65], 1], axis=0)) / norm_distance_y - features["mouth_open"] = self.mouth_open.update(f, now) + f = (np.mean([pts[59, 1], pts[60, 1], pts[61, 1]]) - np.mean([pts[65, 1], pts[64, 1], pts[63, 1]])) / norm_distance_y + features["mouth_open"] = self.mouth_open.update(f) f = abs(pts[58, 0] - pts[62, 0]) / norm_distance_x - features["mouth_wide"] = self.mouth_wide.update(f, now) + features["mouth_wide"] = self.mouth_wide.update(f) return features @@ -328,10 +287,8 @@ class FaceInfo(): self.id = id self.frame_count = -1 self.tracker = tracker - self.contour_pts = [0,1,8,15,16,27,28,29,30,31,32,33,34,35] + self.contour_pts = [0,1,8,15,16,27,28,29,30,31,32,33,34,35,36,39,42,45] self.face_3d = copy.copy(self.tracker.face_3d) - if self.tracker.model_type == -1: - self.contour_pts = [0,2,8,14,16,27,30,33] self.reset() self.alive = False self.coord = None @@ -342,9 +299,6 @@ class FaceInfo(): self.update_count_delta = 75. self.update_count_max = 7500. - if self.tracker.max_feature_updates > 0: - self.features = FeatureExtractor(self.tracker.max_feature_updates) - def reset(self): self.alive = False self.conf = None @@ -360,8 +314,7 @@ class FaceInfo(): self.eye_blink = None self.bbox = None self.pnp_error = 0 - if self.tracker.max_feature_updates < 1: - self.features = FeatureExtractor(0) + self.features = FeatureExtractor() self.current_features = {} self.contour = np.zeros((21,3)) self.update_counts = np.zeros((66,2)) @@ -401,165 +354,141 @@ class FaceInfo(): if self.conf < 0.4 or self.pnp_error > 300: return - if self.tracker.model_type != -1 and not self.tracker.static_model: - max_runs = 1 - eligible = np.delete(np.arange(0, 66), [30]) - changed_any = False - update_type = -1 - d_o = np.ones((66,)) - d_c = np.ones((66,)) - for runs in range(max_runs): - r = 1.0 + np.random.random_sample((66,3)) * 0.02 - 0.01 - r[30, :] = 1.0 - if self.euler[0] > -165 and self.euler[0] < 145: + max_runs = 1 + eligible = np.delete(np.arange(0, 66), [30]) + changed_any = False + update_type = -1 + d_o = np.ones((66,)) + d_c = np.ones((66,)) + for runs in range(max_runs): + r = 1.0 + np.random.random_sample((66,3)) * 0.02 - 0.01 + r[30, :] = 1.0 + if self.euler[0] > -165 and self.euler[0] < 145: + continue + elif self.euler[1] > -10 and self.euler[1] < 20: + r[:, 2] = 1.0 + update_type = 0 + else: + r[:, 0:2] = 1.0 + if self.euler[2] > 120 or self.euler[2] < 60: continue - elif self.euler[1] > -10 and self.euler[1] < 20: - r[:, 2] = 1.0 - update_type = 0 + # Enable only one side of the points, depending on direction + elif self.euler[1] < -10: + update_type = 1 + r[[0, 1, 2, 3, 4, 5, 6, 7, 17, 18, 19, 20, 21, 31, 32, 36, 37, 38, 39, 40, 41, 48, 49, 56, 57, 58, 59, 65], 2] = 1.0 + eligible = [8, 9, 10, 11, 12, 13, 14, 15, 16, 22, 23, 24, 25, 26, 27, 28, 29, 33, 34, 35, 42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55, 60, 61, 62, 63, 64] else: - r[:, 0:2] = 1.0 - if self.euler[2] > 120 or self.euler[2] < 60: - continue - # Enable only one side of the points, depending on direction - elif self.euler[1] < -10: - update_type = 1 - r[[0, 1, 2, 3, 4, 5, 6, 7, 17, 18, 19, 20, 21, 31, 32, 36, 37, 38, 39, 40, 41, 48, 49, 56, 57, 58, 59, 65], 2] = 1.0 - eligible = [8, 9, 10, 11, 12, 13, 14, 15, 16, 22, 23, 24, 25, 26, 27, 28, 29, 33, 34, 35, 42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55, 60, 61, 62, 63, 64] - else: - update_type = 1 - r[[9, 10, 11, 12, 13, 14, 15, 16, 22, 23, 24, 25, 26, 34, 35, 42, 43, 44, 45, 46, 47, 51, 52, 53, 54, 61, 62, 63], 2] = 1.0 - eligible = [0, 1, 2, 3, 4, 5, 6, 7, 8, 17, 18, 19, 20, 21, 27, 28, 29, 31, 32, 33, 36, 37, 38, 39, 40, 41, 48, 49, 50, 55, 56, 57, 58, 59, 60, 64, 65] + update_type = 1 + r[[9, 10, 11, 12, 13, 14, 15, 16, 22, 23, 24, 25, 26, 34, 35, 42, 43, 44, 45, 46, 47, 51, 52, 53, 54, 61, 62, 63], 2] = 1.0 + eligible = [0, 1, 2, 3, 4, 5, 6, 7, 8, 17, 18, 19, 20, 21, 27, 28, 29, 31, 32, 33, 36, 37, 38, 39, 40, 41, 48, 49, 50, 55, 56, 57, 58, 59, 60, 64, 65] - if self.limit_3d_adjustment: - eligible = np.nonzero(self.update_counts[:, update_type] < self.update_counts[:, abs(update_type - 1)] + self.update_count_delta)[0] - if eligible.shape[0] <= 0: - break - - if runs == 0: - updated = copy.copy(self.face_3d[0:66]) - o_projected = np.ones((66,2)) - o_projected[eligible] = np.squeeze(np.array(cv2.projectPoints(self.face_3d[eligible], self.rotation, self.translation, self.tracker.camera, self.tracker.dist_coeffs)[0]), 1) - c = updated * r - c_projected = np.zeros((66,2)) - c_projected[eligible] = np.squeeze(np.array(cv2.projectPoints(c[eligible], self.rotation, self.translation, self.tracker.camera, self.tracker.dist_coeffs)[0]), 1) - changed = False - - d_o[eligible] = np.linalg.norm(o_projected[eligible] - self.lms[eligible, 0:2], axis=1) - d_c[eligible] = np.linalg.norm(c_projected[eligible] - self.lms[eligible, 0:2], axis=1) - indices = np.nonzero(d_c < d_o)[0] - if indices.shape[0] > 0: - if self.limit_3d_adjustment: - indices = np.intersect1d(indices, eligible) - if indices.shape[0] > 0: - self.update_counts[indices, update_type] += 1 - updated[indices] = c[indices] - o_projected[indices] = c_projected[indices] - changed = True - changed_any = changed_any or changed - - if not changed: + if self.limit_3d_adjustment: + eligible = np.nonzero(self.update_counts[:, update_type] < self.update_counts[:, abs(update_type - 1)] + self.update_count_delta)[0] + if eligible.shape[0] <= 0: break - if changed_any: - # Update weighted by point confidence - weights = np.zeros((66,3)) - weights[:, :] = self.lms[0:66, 2:3] - weights[weights > 0.7] = 1.0 - weights = 1.0 - weights - update_indices = np.arange(0, 66) + if runs == 0: + updated = copy.copy(self.face_3d[0:66]) + o_projected = np.ones((66,2)) + o_projected[eligible] = np.squeeze(np.array(cv2.projectPoints(self.face_3d[eligible], self.rotation, self.translation, self.tracker.camera, self.tracker.dist_coeffs)[0]), 1) + c = updated * r + c_projected = np.zeros((66,2)) + c_projected[eligible] = np.squeeze(np.array(cv2.projectPoints(c[eligible], self.rotation, self.translation, self.tracker.camera, self.tracker.dist_coeffs)[0]), 1) + changed = False + + d_o[eligible] = np.linalg.norm(o_projected[eligible] - self.lms[eligible, 0:2], axis=1) + d_c[eligible] = np.linalg.norm(c_projected[eligible] - self.lms[eligible, 0:2], axis=1) + indices = np.nonzero(d_c < d_o)[0] + if indices.shape[0] > 0: if self.limit_3d_adjustment: - update_indices = np.nonzero(self.update_counts[:, update_type] <= self.update_count_max)[0] - self.face_3d[update_indices] = self.face_3d[update_indices] * weights[update_indices] + updated[update_indices] * (1. - weights[update_indices]) - self.update_contour() + indices = np.intersect1d(indices, eligible) + if indices.shape[0] > 0: + self.update_counts[indices, update_type] += 1 + updated[indices] = c[indices] + o_projected[indices] = c_projected[indices] + changed = True + changed_any = changed_any or changed + + if not changed: + break + + if changed_any: + # Update weighted by point confidence + weights = np.zeros((66,3)) + weights[:, :] = self.lms[0:66, 2:3] + weights[weights > 0.7] = 1.0 + weights = 1.0 - weights + update_indices = np.arange(0, 66) + if self.limit_3d_adjustment: + update_indices = np.nonzero(self.update_counts[:, update_type] <= self.update_count_max)[0] + self.face_3d[update_indices] = self.face_3d[update_indices] * weights[update_indices] + updated[update_indices] * (1. - weights[update_indices]) + self.update_contour() self.pts_3d = self.normalize_pts3d(self.pts_3d) - if self.tracker.feature_level == 2: - self.current_features = self.features.update(self.pts_3d[:, 0:2]) - self.eye_blink = [] - self.eye_blink.append(1 - min(max(0, -self.current_features["eye_r"]), 1)) - self.eye_blink.append(1 - min(max(0, -self.current_features["eye_l"]), 1)) - elif self.tracker.feature_level == 1: - self.current_features = self.features.update(self.pts_3d[:, 0:2], False) - self.eye_blink = [] - self.eye_blink.append(1 - min(max(0, -self.current_features["eye_r"]), 1)) - self.eye_blink.append(1 - min(max(0, -self.current_features["eye_l"]), 1)) + self.current_features = self.features.update(self.pts_3d[:, 0:2]) + self.eye_blink = [] + self.eye_blink.append(1 - min(max(0, -self.current_features["eye_r"]), 1)) + self.eye_blink.append(1 - min(max(0, -self.current_features["eye_l"]), 1)) -def get_model_base_path(model_dir): - model_base_path = resolve(os.path.join("models")) - if model_dir is None: - if not os.path.exists(model_base_path): - model_base_path = resolve(os.path.join("..", "models")) - else: - model_base_path = model_dir - return model_base_path class Tracker(): - def __init__(self, width, height, model_type=3, detection_threshold=0.6, threshold=None, max_faces=1, discard_after=5, scan_every=3, bbox_growth=0.0, max_threads=4, silent=False, model_dir=None, no_gaze=False, use_retinaface=False, max_feature_updates=0, static_model=False, feature_level=2, try_hard=False): + def __init__(self, width, height, model_type=3, threshold=0.6, max_faces=1, discard_after=5, scan_every=3, bbox_growth=0.0, max_threads=4, silent=False, model_dir=None, no_gaze=False, use_retinaface=False): options = onnxruntime.SessionOptions() options.inter_op_num_threads = 1 - options.intra_op_num_threads = min(max_threads,4) + options.intra_op_num_threads = max(max_threads,4) options.execution_mode = onnxruntime.ExecutionMode.ORT_SEQUENTIAL options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL options.log_severity_level = 3 self.model_type = model_type self.models = [ - "lm_model0_opt.onnx", - "lm_model1_opt.onnx", - "lm_model2_opt.onnx", - "lm_model3_opt.onnx", - "lm_model4_opt.onnx" + "mnv3_opt_very_fast.onnx", + "mnv3_opt_fast.onnx", + "mnv3_opt_medium.onnx", + "mnv3_opt_b.onnx" ] - model = "lm_modelT_opt.onnx" - if model_type >= 0: - model = self.models[self.model_type] - if model_type == -2: - model = "lm_modelV_opt.onnx" - if model_type == -3: - model = "lm_modelU_opt.onnx" - model_base_path = get_model_base_path(model_dir) - - if threshold is None: - threshold = 0.6 - if model_type < 0: - threshold = 0.87 + model = self.models[self.model_type] + model_base_path = resolve(os.path.join("models")) + if model_dir is None: + if not os.path.exists(model_base_path): + model_base_path = resolve(os.path.join("..", "models")) + else: + model_base_path = model_dir self.retinaface = RetinaFaceDetector(model_path=os.path.join(model_base_path, "retinaface_640x640_opt.onnx"), json_path=os.path.join(model_base_path, "priorbox_640x640.json"), threads=max(max_threads,4), top_k=max_faces, res=(640, 640)) self.retinaface_scan = RetinaFaceDetector(model_path=os.path.join(model_base_path, "retinaface_640x640_opt.onnx"), json_path=os.path.join(model_base_path, "priorbox_640x640.json"), threads=2, top_k=max_faces, res=(640, 640)) self.use_retinaface = use_retinaface - # OTR 1.9 and later requires specifying providers - # explicitly as an argument in InferenceSession() - providersList = onnxruntime.capi._pybind_state.get_available_providers() - # Single face instance with multiple threads - self.session = onnxruntime.InferenceSession(os.path.join(model_base_path, model), sess_options=options, providers=providersList) + self.session = onnxruntime.InferenceSession(os.path.join(model_base_path, model), sess_options=options) # Multiple faces with single threads self.sessions = [] - self.max_workers = max(min(max_threads, max_faces), 1) + self.max_workers = min(max_threads, max_faces) extra_threads = max_threads % self.max_workers for i in range(self.max_workers): options = onnxruntime.SessionOptions() options.inter_op_num_threads = 1 - options.intra_op_num_threads = min(max(max_threads // self.max_workers, 4), 1) + options.intra_op_num_threads = max_threads // self.max_workers if options.intra_op_num_threads < 1: options.intra_op_num_threads = 1 elif i < extra_threads: options.intra_op_num_threads += 1 options.execution_mode = onnxruntime.ExecutionMode.ORT_SEQUENTIAL options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL - self.sessions.append(onnxruntime.InferenceSession(os.path.join(model_base_path, model), sess_options=options, providers=providersList)) + self.sessions.append(onnxruntime.InferenceSession(os.path.join(model_base_path, model), sess_options=options)) self.input_name = self.session.get_inputs()[0].name options = onnxruntime.SessionOptions() options.inter_op_num_threads = 1 - options.intra_op_num_threads = 1 + options.intra_op_num_threads = max(max_threads,4) options.execution_mode = onnxruntime.ExecutionMode.ORT_SEQUENTIAL options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL options.log_severity_level = 3 - self.gaze_model = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_gaze32_split_opt.onnx"), sess_options=options, providers=providersList) + self.gaze_model = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_gaze32_split_opt.onnx"), sess_options=options) + options.intra_op_num_threads = 1 + self.gaze_model_single = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_gaze32_split_opt.onnx"), sess_options=options) - self.detection = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_detection_opt.onnx"), sess_options=options, providers=providersList) + self.detection = onnxruntime.InferenceSession(os.path.join(model_base_path, "mnv3_detection_opt.onnx"), sess_options=options) self.faces = [] # Image normalization constants @@ -568,13 +497,6 @@ class Tracker(): self.mean = self.mean / self.std self.std = self.std * 255.0 - self.mean = - self.mean - self.std = 1.0 / self.std - self.mean_32 = np.tile(self.mean, [32, 32, 1]) - self.std_32 = np.tile(self.std, [32, 32, 1]) - self.mean_224 = np.tile(self.mean, [224, 224, 1]) - self.std_224 = np.tile(self.std, [224, 224, 1]) - # PnP solving self.face_3d = np.array([ [ 0.4551769692672 , 0.300895790030204, -0.764429433974752], @@ -658,7 +580,6 @@ class Tracker(): self.width = width self.height = height self.threshold = threshold - self.detection_threshold = detection_threshold self.max_faces = max_faces self.max_threads = max_threads self.discard = 0 @@ -668,44 +589,15 @@ class Tracker(): self.scan_every = scan_every self.bbox_growth = bbox_growth self.silent = silent - self.try_hard = try_hard - self.res = 224. - self.mean_res = self.mean_224 - self.std_res = self.std_224 - if model_type < 0: - self.res = 56. - self.mean_res = np.tile(self.mean, [56, 56, 1]) - self.std_res = np.tile(self.std, [56, 56, 1]) - if model_type < -1: - self.res = 112. - self.mean_res = np.tile(self.mean, [112, 112, 1]) - self.std_res = np.tile(self.std, [112, 112, 1]) self.res_i = int(self.res) - self.out_res = 27. - if model_type < 0: - self.out_res = 6. - if model_type < -1: - self.out_res = 13. - self.out_res_i = int(self.out_res) + 1 - self.logit_factor = 16. - if model_type < 0: - self.logit_factor = 8. - if model_type < -1: - self.logit_factor = 16. - self.no_gaze = no_gaze self.debug_gaze = False - self.feature_level = feature_level - if model_type == -1: - self.feature_level = min(feature_level, 1) - self.max_feature_updates = max_feature_updates - self.static_model = static_model self.face_info = [FaceInfo(id, self) for id in range(max_faces)] self.fail_count = 0 def detect_faces(self, frame): - im = cv2.resize(frame, (224, 224), interpolation=cv2.INTER_LINEAR)[:,:,::-1] * self.std_224 + self.mean_224 + im = cv2.resize(frame, (224, 224), interpolation=cv2.INTER_LINEAR)[:,:,::-1] / self.std - self.mean im = np.expand_dims(im, 0) im = np.transpose(im, (0,3,1,2)) outputs, maxpool = self.detection.run([], {'input': im}) @@ -721,7 +613,7 @@ class Tracker(): x *= 4 y *= 4 r *= 1.0 - if c < self.detection_threshold: + if c < self.threshold: break results.append((x - r, y - r, 2 * r, 2 * r * 1.0)) results = np.array(results).astype(np.float32) @@ -733,41 +625,31 @@ class Tracker(): def landmarks(self, tensor, crop_info): crop_x1, crop_y1, scale_x, scale_y, _ = crop_info avg_conf = 0 + lms = [] res = self.res - 1 - c0, c1, c2 = 66, 132, 198 - if self.model_type == -1: - c0, c1, c2 = 30, 60, 90 - t_main = tensor[0:c0].reshape((c0,self.out_res_i * self.out_res_i)) - t_m = t_main.argmax(1) - indices = np.expand_dims(t_m, 1) - t_conf = np.take_along_axis(t_main, indices, 1).reshape((c0,)) - t_off_x = np.take_along_axis(tensor[c0:c1].reshape((c0,self.out_res_i * self.out_res_i)), indices, 1).reshape((c0,)) - t_off_y = np.take_along_axis(tensor[c1:c2].reshape((c0,self.out_res_i * self.out_res_i)), indices, 1).reshape((c0,)) - t_off_x = res * logit_arr(t_off_x, self.logit_factor) - t_off_y = res * logit_arr(t_off_y, self.logit_factor) - t_x = crop_y1 + scale_y * (res * np.floor(t_m / self.out_res_i) / self.out_res + t_off_x) - t_y = crop_x1 + scale_x * (res * np.floor(np.mod(t_m, self.out_res_i)) / self.out_res + t_off_y) - avg_conf = np.average(t_conf) - lms = np.stack([t_x, t_y, t_conf], 1) - lms[np.isnan(lms).any(axis=1)] = np.array([0.,0.,0.], dtype=np.float32) - if self.model_type == -1: - lms = lms[[0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,6,7,7,8,8,9,10,10,11,11,12,21,21,21,22,23,23,23,23,23,13,14,14,15,16,16,17,18,18,19,20,20,24,25,25,25,26,26,27,27,27,24,24,28,28,28,26,29,29,29]] - #lms[[1,3,4,6,7,9,10,12,13,15,18,20,23,25,38,40,44,46]] += lms[[2,2,5,5,8,8,11,11,14,16,19,21,24,26,39,39,45,45]] - #lms[[3,4,6,7,9,10,12,13]] += lms[[5,5,8,8,11,11,14,14]] - #lms[[1,15,18,20,23,25,38,40,44,46]] /= 2.0 - #lms[[3,4,6,7,9,10,12,13]] /= 3.0 - part_avg = np.mean(np.partition(lms[:,2],3)[0:3]) - if part_avg < 0.65: - avg_conf = part_avg + for i in range(0, 66): + m = int(tensor[i].argmax()) + x = m // 28 + y = m % 28 + conf = float(tensor[i][x,y]) + avg_conf = avg_conf + conf + off_x = res * ((1. * logit(tensor[66 + i][x, y])) - 0.0) + off_y = res * ((1. * logit(tensor[66 * 2 + i][x, y])) - 0.0) + off_x = math.floor(off_x + 0.5) + off_y = math.floor(off_y + 0.5) + lm_x = crop_y1 + scale_y * (res * (float(x) / 27.) + off_x) + lm_y = crop_x1 + scale_x * (res * (float(y) / 27.) + off_y) + lms.append((lm_x,lm_y,conf)) + avg_conf = avg_conf / 66. return (avg_conf, np.array(lms)) def estimate_depth(self, face_info): - lms = np.concatenate((face_info.lms, np.array([[face_info.eye_state[0][1], face_info.eye_state[0][2], face_info.eye_state[0][3]], [face_info.eye_state[1][1], face_info.eye_state[1][2], face_info.eye_state[1][3]]], np.float32)), 0) + lms = np.concatenate((face_info.lms, np.array([[face_info.eye_state[0][1], face_info.eye_state[0][2], face_info.eye_state[0][3]], [face_info.eye_state[1][1], face_info.eye_state[1][2], face_info.eye_state[1][3]]], np.float)), 0) image_pts = np.array(lms)[face_info.contour_pts, 0:2] success = False - if face_info.rotation is not None: + if not face_info.rotation is None: success, face_info.rotation, face_info.translation = cv2.solvePnP(face_info.contour, image_pts, self.camera, self.dist_coeffs, useExtrinsicGuess=True, rvec=np.transpose(face_info.rotation), tvec=np.transpose(face_info.translation), flags=cv2.SOLVEPNP_ITERATIVE) else: rvec = np.array([0, 0, 0], np.float32) @@ -783,65 +665,54 @@ class Tracker(): face_info.translation = np.array([0.0, 0.0, 0.0], np.float32) return False, np.zeros(4), np.zeros(3), 99999., pts_3d, lms else: - # OpenCV returns (3,1); flatten so [0]/[1]/[2] are scalars for UDP packing - # and 1D .dot() math does not broadcast to (1,3). - face_info.rotation = np.asarray(face_info.rotation, dtype=np.float32).reshape(3) - face_info.translation = np.asarray(face_info.translation, dtype=np.float32).reshape(3) + face_info.rotation = np.transpose(face_info.rotation) + face_info.translation = np.transpose(face_info.translation) rmat, _ = cv2.Rodrigues(rotation) inverse_rotation = np.linalg.inv(rmat) - t_reference = face_info.face_3d.dot(rmat.transpose()) - t_reference = t_reference + face_info.translation - t_reference = t_reference.dot(self.camera.transpose()) - t_depth = t_reference[:, 2] - t_depth[t_depth == 0] = 0.000001 - t_depth_e = np.expand_dims(t_depth[:],1) - t_reference = t_reference[:] / t_depth_e - pts_3d[0:66] = np.stack([lms[0:66,0], lms[0:66,1], np.ones((66,))], 1) * t_depth_e[0:66] - pts_3d[0:66] = (pts_3d[0:66].dot(self.inverse_camera.transpose()) - face_info.translation).dot(inverse_rotation.transpose()) - pnp_error = np.power(lms[0:17,0:2] - t_reference[0:17,0:2], 2).sum() - pnp_error += np.power(lms[30,0:2] - t_reference[30,0:2], 2).sum() - if np.isnan(pnp_error): - pnp_error = 9999999. - for i, pt in enumerate(face_info.face_3d[66:70]): - if i == 2: + pnp_error = 0.0 + for i, pt in enumerate(face_info.face_3d): + if i == 68: # Right eyeball # Eyeballs have an average diameter of 12.5mm and and the distance between eye corners is 30-35mm, so a conversion factor of 0.385 can be applied eye_center = (pts_3d[36] + pts_3d[39]) / 2.0 d_corner = np.linalg.norm(pts_3d[36] - pts_3d[39]) depth = 0.385 * d_corner pt_3d = np.array([eye_center[0], eye_center[1], eye_center[2] - depth]) - pts_3d[68] = pt_3d + pts_3d[i] = pt_3d continue - if i == 3: + if i == 69: # Left eyeball eye_center = (pts_3d[42] + pts_3d[45]) / 2.0 d_corner = np.linalg.norm(pts_3d[42] - pts_3d[45]) depth = 0.385 * d_corner pt_3d = np.array([eye_center[0], eye_center[1], eye_center[2] - depth]) - pts_3d[69] = pt_3d + pts_3d[i] = pt_3d continue - if i == 0: - d1 = np.linalg.norm(lms[66,0:2] - lms[36,0:2]) - d2 = np.linalg.norm(lms[66,0:2] - lms[39,0:2]) + if i == 66: + d1 = np.linalg.norm(lms[i,0:2] - lms[36,0:2]) + d2 = np.linalg.norm(lms[i,0:2] - lms[39,0:2]) d = d1 + d2 pt = (pts_3d[36] * d1 + pts_3d[39] * d2) / d - if i == 1: - d1 = np.linalg.norm(lms[67,0:2] - lms[42,0:2]) - d2 = np.linalg.norm(lms[67,0:2] - lms[45,0:2]) + if i == 67: + d1 = np.linalg.norm(lms[i,0:2] - lms[42,0:2]) + d2 = np.linalg.norm(lms[i,0:2] - lms[45,0:2]) d = d1 + d2 pt = (pts_3d[42] * d1 + pts_3d[45] * d2) / d - if i < 2: - reference = rmat.dot(pt) - reference = reference + face_info.translation - reference = self.camera.dot(reference) - depth = float(reference[2]) - pt_3d = np.array([lms[66+i][0] * depth, lms[66+i][1] * depth, depth], np.float32) - pt_3d = self.inverse_camera.dot(pt_3d) - pt_3d = pt_3d - face_info.translation - pt_3d = inverse_rotation.dot(pt_3d) - pts_3d[66+i,:] = pt_3d[:] - pts_3d[np.isnan(pts_3d).any(axis=1)] = np.array([0.,0.,0.], dtype=np.float32) + reference = rmat.dot(pt) + reference = reference + face_info.translation + reference = self.camera.dot(reference) + depth = reference[2] + if i < 17 or i == 30: + reference = reference / depth + e1 = lms[i][0] - reference[0] + e2 = lms[i][1] - reference[1] + pnp_error += e1*e1 + e2*e2 + pt_3d = np.array([lms[i][0] * depth, lms[i][1] * depth, depth], np.float32) + pt_3d = self.inverse_camera.dot(pt_3d) + pt_3d = pt_3d - face_info.translation + pt_3d = inverse_rotation.dot(pt_3d) + pts_3d[i,:] = pt_3d[:] pnp_error = np.sqrt(pnp_error / (2.0 * image_pts.shape[0])) if pnp_error > 300: @@ -864,7 +735,9 @@ class Tracker(): def preprocess(self, im, crop): x1, y1, x2, y2 = crop im = np.float32(im[y1:y2, x1:x2,::-1]) # Crop and BGR to RGB - im = cv2.resize(im, (self.res_i, self.res_i), interpolation=cv2.INTER_LINEAR) * self.std_res + self.mean_res + im = cv2.resize(im, (self.res_i, self.res_i), interpolation=cv2.INTER_LINEAR) / self.std - self.mean + #im = cv2.resize(im, (224, 224), interpolation=cv2.INTER_LINEAR) / 255.0 + #im = (im - mean) / std im = np.expand_dims(im, 0) im = np.transpose(im, (0,3,1,2)) return im @@ -905,7 +778,7 @@ class Tracker(): full_frame[0:32, 0:32] = im else: full_frame[0:32, 32:64] = im - im = im.astype(np.float32)[:,:,::-1] * self.std_32 + self.mean_32 + im = im.astype(np.float32)[:,:,::-1] / self.std - self.mean im = np.expand_dims(im, 0) im = np.transpose(im, (0,3,2,1)) return im, x1, y1, scale, reference, a @@ -922,11 +795,11 @@ class Tracker(): x1, y1 = clamp_to_im(center - radius, h, w) x2, y2 = clamp_to_im(center + radius + 1, h, w) offset = np.array((x1, y1)) - lms = (lms[:, 0:2] - offset).astype(int) + lms = (lms[:, 0:2] - offset).astype(np.int) frame = frame[y1:y2, x1:x2] return frame, lms, offset - def get_eye_state(self, frame, lms): + def get_eye_state(self, frame, lms, single=False): if self.no_gaze: return [(1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0)] lms = np.array(lms) @@ -942,7 +815,10 @@ class Tracker(): return [(1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0)] both_eyes = np.concatenate((right_eye, left_eye)) results = None - results = self.gaze_model.run([], {self.input_name: both_eyes}) + if single: + results = self.gaze_model_single.run([], {self.input_name: both_eyes}) + else: + results = self.gaze_model.run([], {self.input_name: both_eyes}) open = [0, 0] open[0] = 1#results[1][0].argmax() open[1] = 1#results[1][1].argmax() @@ -986,15 +862,9 @@ class Tracker(): eye_y = eye_y + offset[1] eye_state.append([open[i], eye_y, eye_x, conf]) - eye_state = np.array(eye_state) - eye_state[np.isnan(eye_state).any(axis=1)] = np.array([1.,0.,0.,0.], dtype=np.float32) return eye_state def assign_face_info(self, results): - if self.max_faces == 1 and len(results) == 1: - conf, (lms, eye_state), conf_adjust = results[0] - self.face_info[0].update((conf - conf_adjust, (lms, eye_state)), np.array(lms)[:, 0:2].mean(0), self.frame_count) - return result_coords = [] adjusted_results = [] for conf, (lms, eye_state), conf_adjust in results: @@ -1049,13 +919,11 @@ class Tracker(): self.wait_count += 1 if self.detected == 0: start_fd = time.perf_counter() - if self.use_retinaface > 0 or self.try_hard: + if self.use_retinaface > 0: retinaface_detections = self.retinaface.detect_retina(frame) new_faces.extend(retinaface_detections) - if self.use_retinaface == 0 or self.try_hard: + else: new_faces.extend(self.detect_faces(frame)) - if self.try_hard: - new_faces.extend([(0, 0, self.width, self.height)]) duration_fd = 1000 * (time.perf_counter() - start_fd) self.wait_count = 0 elif self.detected < self.max_faces: @@ -1109,10 +977,7 @@ class Tracker(): output = self.session.run([], {self.input_name: crops[0]})[0] conf, lms = self.landmarks(output[0], crop_info[0]) if conf > self.threshold: - try: - eye_state = self.get_eye_state(frame, lms) - except: - eye_state = [(1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0)] + eye_state = self.get_eye_state(frame, lms) outputs[crop_info[0]] = (conf, (lms, eye_state), 0) else: started = 0 @@ -1174,8 +1039,8 @@ class Tracker(): face_info.success, face_info.quaternion, face_info.euler, face_info.pnp_error, face_info.pts_3d, face_info.lms = self.estimate_depth(face_info) face_info.adjust_3d() lms = face_info.lms[:, 0:2] - x1, y1 = tuple(lms[0:66].min(0)) - x2, y2 = tuple(lms[0:66].max(0)) + x1, y1 = tuple(lms.min(0)) + x2, y2 = tuple(lms.max(0)) bbox = (y1, x1, y2 - y1, x2 - x1) face_info.bbox = bbox detected.append(bbox) @@ -1201,12 +1066,10 @@ class Tracker(): h += 2 * h * self.bbox_growth faces.append((x,y,w,h)) self.faces = faces - self.faces = [x for x in self.faces if not np.isnan(np.array(x)).any()] - self.detected = len(self.faces) duration = (time.perf_counter() - start) * 1000 if not self.silent: - print(f"Took {duration:.2f}ms (detect: {duration_fd:.2f}ms, crop: {duration_pp:.2f}ms, track: {duration_model:.2f}ms, 3D points: {duration_pnp:.2f}ms)") + print(f"Took {duration:.2f}ms (detect: {duration_fd:.2f}ms, crop: {duration_pp:.2f}, track: {duration_model:.2f}ms, 3D points: {duration_pnp:.2f}ms)") results = sorted(results, key=lambda x: x.id)