FiE-Game/Assets/Cinematic Effects/MotionBlur/Plugins/SkinnedState.cs

848 lines
27 KiB
C#

// Amplify Motion - Full-scene Motion Blur for Unity Pro
// Copyright (c) Amplify Creations, Lda <info@amplify.pt>
#if UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9
#define UNITY_4
#endif
#if UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 || UNITY_5_6 || UNITY_5_7 || UNITY_5_8 || UNITY_5_9
#define UNITY_5
#endif
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using UnityEngine;
using UnityEngine.Profiling;
#if !UNITY_4
using UnityEngine.Rendering;
#endif
namespace AmplifyMotion
{
internal class SkinnedState : AmplifyMotion.MotionState
{
private SkinnedMeshRenderer m_renderer;
private int m_boneCount;
private Transform[] m_boneTransforms;
private Matrix4x4[] m_bones;
private int m_weightCount;
private int[] m_boneIndices;
private float[] m_boneWeights;
private int m_vertexCount;
private Vector4[] m_baseVertices;
private Vector3[] m_prevVertices;
private Vector3[] m_currVertices;
#if !UNITY_4
private int m_gpuBoneTexWidth;
private int m_gpuBoneTexHeight;
private int m_gpuVertexTexWidth;
private int m_gpuVertexTexHeight;
private Material m_gpuSkinDeformMat;
private Color[] m_gpuBoneData;
private Texture2D m_gpuBones;
private Texture2D m_gpuBoneIndices;
private Texture2D[] m_gpuBaseVertices;
private RenderTexture m_gpuPrevVertices;
private RenderTexture m_gpuCurrVertices;
#endif
private Mesh m_clonedMesh;
private Matrix4x4 m_worldToLocalMatrix;
private Matrix4x4 m_prevLocalToWorld;
private Matrix4x4 m_currLocalToWorld;
private MaterialDesc[] m_sharedMaterials;
private ManualResetEvent m_asyncUpdateSignal = null;
private bool m_asyncUpdateTriggered = false;
private bool m_starting;
private bool m_wasVisible;
private bool m_useFallback;
private bool m_useGPU = false;
private static HashSet<AmplifyMotionObjectBase> m_uniqueWarnings = new HashSet<AmplifyMotionObjectBase>();
public SkinnedState( AmplifyMotionCamera owner, AmplifyMotionObjectBase obj )
: base( owner, obj )
{
m_renderer = m_obj.GetComponent<SkinnedMeshRenderer>();
}
internal override void Initialize()
{
if ( !m_renderer.sharedMesh.isReadable )
{
if ( !m_uniqueWarnings.Contains( m_obj ) )
{
Debug.LogWarning( "[AmplifyMotion] Read/Write Import Setting disabled in object " + m_obj.name + ". Skipping." );
m_uniqueWarnings.Add( m_obj );
}
m_error = true;
return;
}
// find out if we're forced to use the fallback path
Transform[] bones = m_renderer.bones;
m_useFallback = ( bones == null || bones.Length == 0 );
if ( !m_useFallback )
m_useGPU = m_owner.Instance.CanUseGPU; // use GPU, if allowed
base.Initialize();
m_vertexCount = m_renderer.sharedMesh.vertexCount;
m_prevVertices = new Vector3[ m_vertexCount ];
m_currVertices = new Vector3[ m_vertexCount ];
m_clonedMesh = new Mesh();
if ( !m_useFallback )
{
if ( m_renderer.quality == SkinQuality.Auto )
m_weightCount = ( int ) QualitySettings.blendWeights;
else
m_weightCount = ( int ) m_renderer.quality;
m_boneTransforms = m_renderer.bones;
m_boneCount = m_renderer.bones.Length;
m_bones = new Matrix4x4[ m_boneCount ];
Vector4[] baseVertices = new Vector4[ m_vertexCount * m_weightCount ];
int[] boneIndices = new int[ m_vertexCount * m_weightCount ];
float[] boneWeights = ( m_weightCount > 1 ) ? new float[ m_vertexCount * m_weightCount ] : null;
if ( m_weightCount == 1 )
InitializeBone1( baseVertices, boneIndices );
else if ( m_weightCount == 2 )
InitializeBone2( baseVertices, boneIndices, boneWeights );
else
InitializeBone4( baseVertices, boneIndices, boneWeights );
m_baseVertices = baseVertices;
m_boneIndices = boneIndices;
m_boneWeights = boneWeights;
Mesh skinnedMesh = m_renderer.sharedMesh;
m_clonedMesh.vertices = skinnedMesh.vertices;
m_clonedMesh.normals = skinnedMesh.vertices;
m_clonedMesh.uv = skinnedMesh.uv;
m_clonedMesh.subMeshCount = skinnedMesh.subMeshCount;
for ( int i = 0; i < skinnedMesh.subMeshCount; i++ )
m_clonedMesh.SetTriangles( skinnedMesh.GetTriangles( i ), i );
#if !UNITY_4
if ( m_useGPU )
{
if ( !InitializeGPUSkinDeform() )
{
// fallback
Debug.LogWarning( "[AmplifyMotion] Failed initializing GPU skin deform for object " + m_obj.name + ". Falling back to CPU path." );
m_useGPU = false;
}
else
{
// release unnecessary data
m_boneIndices = null;
m_boneWeights = null;
m_baseVertices = null;
m_prevVertices = null;
m_currVertices = null;
}
}
#endif
if ( !m_useGPU )
{
m_asyncUpdateSignal = new ManualResetEvent( false );
m_asyncUpdateTriggered = false;
}
}
m_sharedMaterials = ProcessSharedMaterials( m_renderer.sharedMaterials );
m_wasVisible = false;
}
internal override void Shutdown()
{
if ( !m_useFallback && !m_useGPU )
WaitForAsyncUpdate();
#if !UNITY_4
if ( m_useGPU )
ShutdownGPUSkinDeform();
#endif
if ( m_clonedMesh != null )
{
Mesh.Destroy( m_clonedMesh );
m_clonedMesh = null;
}
m_boneTransforms = null;
m_bones = null;
m_boneIndices = null;
m_boneWeights = null;
m_baseVertices = null;
m_prevVertices = null;
m_currVertices = null;
m_sharedMaterials = null;
}
#if !UNITY_4
private bool InitializeGPUSkinDeform()
{
bool succeeded = true;
try
{
m_gpuBoneTexWidth = Mathf.NextPowerOfTwo( m_boneCount );
m_gpuBoneTexHeight = 4;
m_gpuVertexTexWidth = Mathf.NextPowerOfTwo( Mathf.CeilToInt( Mathf.Sqrt( m_vertexCount ) ) );
m_gpuVertexTexHeight = Mathf.NextPowerOfTwo( Mathf.CeilToInt( m_vertexCount / ( float ) m_gpuVertexTexWidth ) );
// gpu skin deform material
m_gpuSkinDeformMat = new Material( Shader.Find( "Hidden/Amplify Motion/GPUSkinDeform" ) ) { hideFlags = HideFlags.DontSave };
// bone matrix texture
m_gpuBones = new Texture2D( m_gpuBoneTexWidth, m_gpuBoneTexHeight, TextureFormat.RGBAFloat, false, true );
m_gpuBones.hideFlags = HideFlags.DontSave;
m_gpuBones.name = "AM-" + m_obj.name + "-Bones";
m_gpuBones.filterMode = FilterMode.Point;
m_gpuBoneData = new Color[ m_gpuBoneTexWidth * m_gpuBoneTexHeight ];
UpdateBonesGPU();
// vertex bone index/weight textures
TextureFormat boneIDWFormat = TextureFormat.RHalf;
boneIDWFormat = ( m_weightCount == 2 ) ? TextureFormat.RGHalf : boneIDWFormat;
boneIDWFormat = ( m_weightCount == 4 ) ? TextureFormat.RGBAHalf : boneIDWFormat;
m_gpuBoneIndices = new Texture2D( m_gpuVertexTexWidth, m_gpuVertexTexHeight, boneIDWFormat, false, true );
m_gpuBoneIndices.hideFlags = HideFlags.DontSave;
m_gpuBoneIndices.name = "AM-" + m_obj.name + "-Bones";
m_gpuBoneIndices.filterMode = FilterMode.Point;
m_gpuBoneIndices.wrapMode = TextureWrapMode.Clamp;
BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights;
Color[] boneIndices = new Color[ m_gpuVertexTexWidth * m_gpuVertexTexHeight ];
for ( int v = 0; v < m_vertexCount; v++ )
{
int x = v % m_gpuVertexTexWidth;
int y = v / m_gpuVertexTexWidth;
int offset = y * m_gpuVertexTexWidth + x;
BoneWeight boneWeight = meshBoneWeights[ v ];
boneIndices[ offset ] = new Vector4( boneWeight.boneIndex0, boneWeight.boneIndex1, boneWeight.boneIndex2, boneWeight.boneIndex3 );
}
m_gpuBoneIndices.SetPixels( boneIndices );
m_gpuBoneIndices.Apply();
// base vertex textures
m_gpuBaseVertices = new Texture2D[ m_weightCount ];
for ( int w = 0; w < m_weightCount; w++ )
{
m_gpuBaseVertices[ w ] = new Texture2D( m_gpuVertexTexWidth, m_gpuVertexTexHeight, TextureFormat.RGBAFloat, false, true );
m_gpuBaseVertices[ w ].hideFlags = HideFlags.DontSave;
m_gpuBaseVertices[ w ].name = "AM-" + m_obj.name + "-BaseVerts";
m_gpuBaseVertices[ w ].filterMode = FilterMode.Point;
}
List<Color[]> baseVertices = new List<Color[]>( m_weightCount );
for ( int w = 0; w < m_weightCount; w++ )
baseVertices.Add( new Color[ m_gpuVertexTexWidth * m_gpuVertexTexHeight ] );
for ( int v = 0; v < m_vertexCount; v++ )
{
int x = v % m_gpuVertexTexWidth;
int y = v / m_gpuVertexTexWidth;
int offset = y * m_gpuVertexTexWidth + x;
for ( int w = 0; w < m_weightCount; w++ )
baseVertices[ w ][ offset ] = m_baseVertices[ v * m_weightCount + w ];
}
for ( int w = 0; w < m_weightCount; w++ )
{
m_gpuBaseVertices[ w ].SetPixels( baseVertices[ w ] );
m_gpuBaseVertices[ w ].Apply();
}
// create output/target vertex render textures
m_gpuPrevVertices = new RenderTexture( m_gpuVertexTexWidth, m_gpuVertexTexHeight, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear );
m_gpuPrevVertices.hideFlags = HideFlags.DontSave;
m_gpuPrevVertices.name = "AM-" + m_obj.name + "-PrevVerts";
m_gpuPrevVertices.filterMode = FilterMode.Point;
m_gpuPrevVertices.wrapMode = TextureWrapMode.Clamp;
m_gpuPrevVertices.Create();
m_gpuCurrVertices = new RenderTexture( m_gpuVertexTexWidth, m_gpuVertexTexHeight, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear );
m_gpuCurrVertices.hideFlags = HideFlags.DontSave;
m_gpuCurrVertices.name = "AM-" + m_obj.name + "-CurrVerts";
m_gpuCurrVertices.filterMode = FilterMode.Point;
m_gpuCurrVertices.wrapMode = TextureWrapMode.Clamp;
m_gpuCurrVertices.Create();
// assign local material constants
m_gpuSkinDeformMat.SetTexture( "_AM_BONE_TEX", m_gpuBones );
m_gpuSkinDeformMat.SetTexture( "_AM_BONE_INDEX_TEX", m_gpuBoneIndices );
for ( int w = 0; w < m_weightCount; w++ )
m_gpuSkinDeformMat.SetTexture( "_AM_BASE_VERTEX" + w + "_TEX", m_gpuBaseVertices[ w ] );
// assign global shader constants
Vector4 boneTexelSize = new Vector4( 1.0f / m_gpuBoneTexWidth, 1.0f / m_gpuBoneTexHeight, m_gpuBoneTexWidth, m_gpuBoneTexHeight );
Vector4 vertexTexelSize = new Vector4( 1.0f / m_gpuVertexTexWidth, 1.0f / m_gpuVertexTexHeight, m_gpuVertexTexWidth, m_gpuVertexTexHeight );
m_gpuSkinDeformMat.SetVector( "_AM_BONE_TEXEL_SIZE", boneTexelSize );
m_gpuSkinDeformMat.SetVector( "_AM_BONE_TEXEL_HALFSIZE", boneTexelSize * 0.5f );
m_gpuSkinDeformMat.SetVector( "_AM_VERTEX_TEXEL_SIZE", vertexTexelSize );
m_gpuSkinDeformMat.SetVector( "_AM_VERTEX_TEXEL_HALFSIZE", vertexTexelSize * 0.5f );
// assign vertex x/y offsets packed into second uv channel
Vector2[] indexCoords = new Vector2[ m_vertexCount ];
for ( int v = 0; v < m_vertexCount; v++ )
{
int x = v % m_gpuVertexTexWidth;
int y = v / m_gpuVertexTexWidth;
float x_norm = ( x / ( float ) m_gpuVertexTexWidth ) + vertexTexelSize.x * 0.5f;
float y_norm = ( y / ( float ) m_gpuVertexTexHeight ) + vertexTexelSize.y * 0.5f;
indexCoords[ v ] = new Vector2( x_norm, y_norm );
}
m_clonedMesh.uv2 = indexCoords;
}
catch ( Exception )
{
succeeded = false;
}
return succeeded;
}
private void ShutdownGPUSkinDeform()
{
if ( m_gpuSkinDeformMat != null )
{
Material.DestroyImmediate( m_gpuSkinDeformMat );
m_gpuSkinDeformMat = null;
}
m_gpuBoneData = null;
if ( m_gpuBones != null )
{
Texture2D.DestroyImmediate( m_gpuBones );
m_gpuBones = null;
}
if ( m_gpuBoneIndices != null )
{
Texture2D.DestroyImmediate( m_gpuBoneIndices );
m_gpuBoneIndices = null;
}
if ( m_gpuBaseVertices != null )
{
for ( int i = 0; i < m_gpuBaseVertices.Length; i++ )
Texture2D.DestroyImmediate( m_gpuBaseVertices[ i ] );
m_gpuBaseVertices = null;
}
if ( m_gpuPrevVertices != null )
{
RenderTexture.active = null;
m_gpuPrevVertices.Release();
RenderTexture.DestroyImmediate( m_gpuPrevVertices );
m_gpuPrevVertices = null;
}
if ( m_gpuCurrVertices != null )
{
RenderTexture.active = null;
m_gpuCurrVertices.Release();
RenderTexture.DestroyImmediate( m_gpuCurrVertices );
m_gpuCurrVertices = null;
}
}
private void UpdateBonesGPU()
{
for ( int b = 0; b < m_boneCount; b++ )
{
for ( int r = 0; r < m_gpuBoneTexHeight; r++ )
m_gpuBoneData[ r * m_gpuBoneTexWidth + b ] = m_bones[ b ].GetRow( r );
}
m_gpuBones.SetPixels( m_gpuBoneData );
m_gpuBones.Apply();
}
private void UpdateVerticesGPU( CommandBuffer updateCB, bool starting )
{
if ( !starting && m_wasVisible )
{
AmplifyMotionEffectBase.DiscardContents( m_gpuPrevVertices );
updateCB.Blit( new RenderTargetIdentifier( m_gpuCurrVertices ), m_gpuPrevVertices );
}
updateCB.SetGlobalMatrix( "_AM_WORLD_TO_LOCAL_MATRIX", m_worldToLocalMatrix );
AmplifyMotionEffectBase.DiscardContents( m_gpuCurrVertices );
RenderTexture dummy = null;
updateCB.Blit( new RenderTargetIdentifier( dummy ), m_gpuCurrVertices, m_gpuSkinDeformMat, Mathf.Min( m_weightCount - 1, 2 ) );
if ( starting || !m_wasVisible )
{
AmplifyMotionEffectBase.DiscardContents( m_gpuPrevVertices );
updateCB.Blit( new RenderTargetIdentifier( m_gpuCurrVertices ), m_gpuPrevVertices );
}
}
#endif
private void UpdateBones()
{
for ( int b = 0; b < m_boneCount; b++ )
m_bones[ b ] = ( m_boneTransforms[ b ] != null ) ? m_boneTransforms[ b ].localToWorldMatrix : Matrix4x4.identity;
m_worldToLocalMatrix = m_transform.worldToLocalMatrix;
#if !UNITY_4
if ( m_useGPU )
{
Profiler.BeginSample( "UpdateBonesGPU" );
UpdateBonesGPU();
Profiler.EndSample();
}
#endif
}
private void UpdateVerticesFallback( bool starting )
{
if ( !starting && m_wasVisible )
Array.Copy( m_currVertices, m_prevVertices, m_vertexCount );
m_renderer.BakeMesh( m_clonedMesh );
Array.Copy( m_clonedMesh.vertices, m_currVertices, m_vertexCount );
if ( starting || !m_wasVisible )
Array.Copy( m_currVertices, m_prevVertices, m_vertexCount );
}
private void AsyncUpdateVertices( bool starting )
{
if ( !starting && m_wasVisible )
Array.Copy( m_currVertices, m_prevVertices, m_vertexCount );
for ( int i = 0; i < m_boneCount; i++ )
m_bones[ i ] = m_worldToLocalMatrix * m_bones[ i ];
if ( m_weightCount == 1 )
UpdateVerticesBone1();
else if ( m_weightCount == 2 )
UpdateVerticesBone2();
else
UpdateVerticesBone4();
if ( starting || !m_wasVisible )
Array.Copy( m_currVertices, m_prevVertices, m_vertexCount );
}
private void InitializeBone1( Vector4[] baseVertices, int[] boneIndices )
{
Vector3[] meshVertices = m_renderer.sharedMesh.vertices;
Matrix4x4[] meshBindPoses = m_renderer.sharedMesh.bindposes;
BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights;
for ( int i = 0; i < m_vertexCount; i++ )
{
int offset0 = i * m_weightCount;
int bone0 = boneIndices[ offset0 ] = meshBoneWeights[ i ].boneIndex0;
Vector3 baseVertex0 = meshBindPoses[ bone0 ].MultiplyPoint3x4( meshVertices[ i ] );
baseVertices[ offset0 ] = new Vector4( baseVertex0.x, baseVertex0.y, baseVertex0.z, 1.0f );
}
}
private void InitializeBone2( Vector4[] baseVertices, int[] boneIndices, float[] boneWeights )
{
Vector3[] meshVertices = m_renderer.sharedMesh.vertices;
Matrix4x4[] meshBindPoses = m_renderer.sharedMesh.bindposes;
BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights;
for ( int i = 0; i < m_vertexCount; i++ )
{
int offset0 = i * m_weightCount;
int offset1 = offset0 + 1;
BoneWeight boneWeight = meshBoneWeights[ i ];
int bone0 = boneIndices[ offset0 ] = boneWeight.boneIndex0;
int bone1 = boneIndices[ offset1 ] = boneWeight.boneIndex1;
float weight0 = boneWeight.weight0;
float weight1 = boneWeight.weight1;
float rcpSum = 1.0f / ( weight0 + weight1 );
boneWeights[ offset0 ] = weight0 = weight0 * rcpSum;
boneWeights[ offset1 ] = weight1 = weight1 * rcpSum;
Vector3 baseVertex0 = weight0 * meshBindPoses[ bone0 ].MultiplyPoint3x4( meshVertices[ i ] );
Vector3 baseVertex1 = weight1 * meshBindPoses[ bone1 ].MultiplyPoint3x4( meshVertices[ i ] );
baseVertices[ offset0 ] = new Vector4( baseVertex0.x, baseVertex0.y, baseVertex0.z, weight0 );
baseVertices[ offset1 ] = new Vector4( baseVertex1.x, baseVertex1.y, baseVertex1.z, weight1 );
}
}
private void InitializeBone4( Vector4[] baseVertices, int[] boneIndices, float[] boneWeights )
{
Vector3[] meshVertices = m_renderer.sharedMesh.vertices;
Matrix4x4[] meshBindPoses = m_renderer.sharedMesh.bindposes;
BoneWeight[] meshBoneWeights = m_renderer.sharedMesh.boneWeights;
for ( int i = 0; i < m_vertexCount; i++ )
{
int offset0 = i * m_weightCount;
int offset1 = offset0 + 1;
int offset2 = offset0 + 2;
int offset3 = offset0 + 3;
BoneWeight boneWeight = meshBoneWeights[ i ];
int bone0 = boneIndices[ offset0 ] = boneWeight.boneIndex0;
int bone1 = boneIndices[ offset1 ] = boneWeight.boneIndex1;
int bone2 = boneIndices[ offset2 ] = boneWeight.boneIndex2;
int bone3 = boneIndices[ offset3 ] = boneWeight.boneIndex3;
float weight0 = boneWeights[ offset0 ] = boneWeight.weight0;
float weight1 = boneWeights[ offset1 ] = boneWeight.weight1;
float weight2 = boneWeights[ offset2 ] = boneWeight.weight2;
float weight3 = boneWeights[ offset3 ] = boneWeight.weight3;
Vector3 baseVertex0 = weight0 * meshBindPoses[ bone0 ].MultiplyPoint3x4( meshVertices[ i ] );
Vector3 baseVertex1 = weight1 * meshBindPoses[ bone1 ].MultiplyPoint3x4( meshVertices[ i ] );
Vector3 baseVertex2 = weight2 * meshBindPoses[ bone2 ].MultiplyPoint3x4( meshVertices[ i ] );
Vector3 baseVertex3 = weight3 * meshBindPoses[ bone3 ].MultiplyPoint3x4( meshVertices[ i ] );
baseVertices[ offset0 ] = new Vector4( baseVertex0.x, baseVertex0.y, baseVertex0.z, weight0 );
baseVertices[ offset1 ] = new Vector4( baseVertex1.x, baseVertex1.y, baseVertex1.z, weight1 );
baseVertices[ offset2 ] = new Vector4( baseVertex2.x, baseVertex2.y, baseVertex2.z, weight2 );
baseVertices[ offset3 ] = new Vector4( baseVertex3.x, baseVertex3.y, baseVertex3.z, weight3 );
}
}
private void UpdateVerticesBone1()
{
for ( int i = 0; i < m_vertexCount; i++ )
MulPoint3x4_XYZ( ref m_currVertices[ i ], ref m_bones[ m_boneIndices[ i ] ], m_baseVertices[ i ] );
}
private void UpdateVerticesBone2()
{
Vector3 deformedVertex = Vector3.zero;
for ( int i = 0; i < m_vertexCount; i++ )
{
int offset0 = i * 2;
int offset1 = offset0 + 1;
int b0 = m_boneIndices[ offset0 ];
int b1 = m_boneIndices[ offset1 ];
float weight1 = m_boneWeights[ offset1 ];
MulPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b0 ], m_baseVertices[ offset0 ] );
if ( weight1 != 0 )
MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b1 ], m_baseVertices[ offset1 ] );
m_currVertices[ i ] = deformedVertex;
}
}
private void UpdateVerticesBone4()
{
Vector3 deformedVertex = Vector3.zero;
for ( int i = 0; i < m_vertexCount; i++ )
{
int offset0 = i * 4;
int offset1 = offset0 + 1;
int offset2 = offset0 + 2;
int offset3 = offset0 + 3;
int b0 = m_boneIndices[ offset0 ];
int b1 = m_boneIndices[ offset1 ];
int b2 = m_boneIndices[ offset2 ];
int b3 = m_boneIndices[ offset3 ];
float weight1 = m_boneWeights[ offset1 ];
float weight2 = m_boneWeights[ offset2 ];
float weight3 = m_boneWeights[ offset3 ];
MulPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b0 ], m_baseVertices[ offset0 ] );
if ( weight1 != 0 )
MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b1 ], m_baseVertices[ offset1 ] );
if ( weight2 != 0 )
MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b2 ], m_baseVertices[ offset2 ] );
if ( weight3 != 0 )
MulAddPoint3x4_XYZW( ref deformedVertex, ref m_bones[ b3 ], m_baseVertices[ offset3 ] );
m_currVertices[ i ] = deformedVertex;
}
}
internal override void AsyncUpdate()
{
try
{
AsyncUpdateVertices( m_starting );
}
catch ( System.Exception e )
{
Debug.LogError( "[AmplifyMotion] Failed on SkinnedMeshRenderer data. Please contact support.\n" + e.Message );
}
finally
{
m_asyncUpdateSignal.Set();
}
}
#if UNITY_4
internal override void UpdateTransform( bool starting )
#else
internal override void UpdateTransform( CommandBuffer updateCB, bool starting )
#endif
{
if ( !m_initialized )
{
Initialize();
return;
}
Profiler.BeginSample( "Skinned.Update" );
if ( !starting && m_wasVisible )
m_prevLocalToWorld = m_currLocalToWorld;
bool isVisible = m_renderer.isVisible;
if ( !m_error && ( isVisible || starting ) )
{
UpdateBones();
m_starting = !m_wasVisible || starting;
if ( !m_useFallback )
{
if ( !m_useGPU )
{
m_asyncUpdateSignal.Reset();
m_asyncUpdateTriggered = true;
m_owner.Instance.WorkerPool.EnqueueAsyncUpdate( this );
}
#if !UNITY_4
else
UpdateVerticesGPU( updateCB, m_starting );
#endif
}
else
UpdateVerticesFallback( m_starting );
}
if ( !m_useFallback )
m_currLocalToWorld = m_transform.localToWorldMatrix;
else
m_currLocalToWorld = Matrix4x4.TRS( m_transform.position, m_transform.rotation, Vector3.one );
if ( starting || !m_wasVisible )
m_prevLocalToWorld = m_currLocalToWorld;
m_wasVisible = isVisible;
Profiler.EndSample();
}
private void WaitForAsyncUpdate()
{
if ( m_asyncUpdateTriggered )
{
if ( !m_asyncUpdateSignal.WaitOne( MotionState.AsyncUpdateTimeout ) )
{
Debug.LogWarning( "[AmplifyMotion] Aborted abnormally long Async Skin deform operation. Not a critical error but might indicate a problem. Please contact support." );
return;
}
m_asyncUpdateTriggered = false;
}
}
#if UNITY_4
internal override void RenderVectors( Camera camera, float scale, AmplifyMotion.Quality quality )
{
if ( m_initialized && !m_error && m_renderer.isVisible )
{
Profiler.BeginSample( "Skinned.Update" );
if ( !m_useFallback )
{
if ( !m_useGPU )
WaitForAsyncUpdate();
}
Profiler.EndSample();
Profiler.BeginSample( "Skinned.Render" );
if ( !m_useGPU )
{
if ( !m_useFallback )
m_clonedMesh.vertices = m_currVertices;
m_clonedMesh.normals = m_prevVertices;
}
const float rcp255 = 1 / 255.0f;
bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0;
int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255;
Matrix4x4 prevModelViewProj;
if ( m_obj.FixedStep )
prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld;
else
prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld;
Shader.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj );
Shader.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 );
Shader.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 );
if ( m_useGPU )
{
#if !UNITY_4
Vector4 vertexTexelSize = new Vector4( 1.0f / m_gpuVertexTexWidth, 1.0f / m_gpuVertexTexHeight, m_gpuVertexTexWidth, m_gpuVertexTexHeight );
Shader.SetGlobalVector( "_AM_VERTEX_TEXEL_SIZE", vertexTexelSize );
Shader.SetGlobalVector( "_AM_VERTEX_TEXEL_HALFSIZE", vertexTexelSize * 0.5f );
Shader.SetGlobalTexture( "_AM_PREV_VERTEX_TEX", m_gpuPrevVertices );
Shader.SetGlobalTexture( "_AM_CURR_VERTEX_TEX", m_gpuCurrVertices );
#endif
}
int hardwarePass = m_useGPU ? 4 : 0;
int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2;
int basePass = hardwarePass + qualityPass;
for ( int i = 0; i < m_sharedMaterials.Length; i++ )
{
MaterialDesc matDesc = m_sharedMaterials[ i ];
int pass = basePass + ( matDesc.coverage ? 1 : 0 );
if ( matDesc.coverage )
{
m_owner.Instance.SkinnedVectorsMaterial.mainTexture = matDesc.material.mainTexture;
if ( matDesc.cutoff )
m_owner.Instance.SkinnedVectorsMaterial.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) );
}
if ( m_owner.Instance.SkinnedVectorsMaterial.SetPass( pass ) )
Graphics.DrawMeshNow( m_clonedMesh, m_currLocalToWorld, i );
}
Profiler.EndSample();
}
}
#else
internal override void RenderVectors( Camera camera, CommandBuffer renderCB, float scale, AmplifyMotion.Quality quality )
{
if ( m_initialized && !m_error && m_renderer.isVisible )
{
Profiler.BeginSample( "Skinned.Update" );
if ( !m_useFallback )
{
if ( !m_useGPU )
WaitForAsyncUpdate();
}
Profiler.EndSample();
Profiler.BeginSample( "Skinned.Render" );
if ( !m_useGPU )
{
if ( !m_useFallback )
m_clonedMesh.vertices = m_currVertices;
m_clonedMesh.normals = m_prevVertices;
}
const float rcp255 = 1 / 255.0f;
bool mask = ( m_owner.Instance.CullingMask & ( 1 << m_obj.gameObject.layer ) ) != 0;
int objectId = mask ? m_owner.Instance.GenerateObjectId( m_obj.gameObject ) : 255;
Matrix4x4 prevModelViewProj;
if ( m_obj.FixedStep )
prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_currLocalToWorld;
else
prevModelViewProj = m_owner.PrevViewProjMatrixRT * m_prevLocalToWorld;
renderCB.SetGlobalMatrix( "_AM_MATRIX_PREV_MVP", prevModelViewProj );
renderCB.SetGlobalFloat( "_AM_OBJECT_ID", objectId * rcp255 );
renderCB.SetGlobalFloat( "_AM_MOTION_SCALE", mask ? scale : 0 );
if ( m_useGPU )
{
#if !UNITY_4
Vector4 vertexTexelSize = new Vector4( 1.0f / m_gpuVertexTexWidth, 1.0f / m_gpuVertexTexHeight, m_gpuVertexTexWidth, m_gpuVertexTexHeight );
renderCB.SetGlobalVector( "_AM_VERTEX_TEXEL_SIZE", vertexTexelSize );
renderCB.SetGlobalVector( "_AM_VERTEX_TEXEL_HALFSIZE", vertexTexelSize * 0.5f );
renderCB.SetGlobalTexture( "_AM_PREV_VERTEX_TEX", m_gpuPrevVertices );
renderCB.SetGlobalTexture( "_AM_CURR_VERTEX_TEX", m_gpuCurrVertices );
#endif
}
int hardwarePass = m_useGPU ? 4 : 0;
int qualityPass = ( quality == AmplifyMotion.Quality.Mobile ) ? 0 : 2;
int basePass = hardwarePass + qualityPass;
for ( int i = 0; i < m_sharedMaterials.Length; i++ )
{
MaterialDesc matDesc = m_sharedMaterials[ i ];
int pass = basePass + ( matDesc.coverage ? 1 : 0 );
if ( matDesc.coverage )
{
Texture mainTex = matDesc.material.mainTexture;
if ( mainTex != null )
matDesc.propertyBlock.SetTexture( "_MainTex", mainTex );
if ( matDesc.cutoff )
matDesc.propertyBlock.SetFloat( "_Cutoff", matDesc.material.GetFloat( "_Cutoff" ) );
}
renderCB.DrawMesh( m_clonedMesh, m_currLocalToWorld, m_owner.Instance.SkinnedVectorsMaterial, i, pass, matDesc.propertyBlock );
}
Profiler.EndSample();
}
}
#endif
//internal override void RenderDebugHUD()
//{
// if ( m_useGPU && m_obj.name.Contains( "Soldier" ) )
// {
// const int size = 180;
// int y = 180;
//
// GUI.DrawTexture( new Rect( 0, y, size, size ), m_gpuBoneIndices, ScaleMode.ScaleToFit, false );
// GUI.DrawTexture( new Rect( size * 2, y, size, size ), m_gpuBones, ScaleMode.ScaleToFit, false );
// y += size + 10;
//
// for ( int w = 0; w < m_weightCount; w++ )
// GUI.DrawTexture( new Rect( w * size, y, size, size ), m_gpuBaseVertices[ w ], ScaleMode.ScaleToFit, false );
//
// GUI.DrawTexture( new Rect( Screen.width - size * 2, y, size, size ), m_gpuPrevVertices, ScaleMode.ScaleToFit, false );
// GUI.DrawTexture( new Rect( Screen.width - size, y, size, size ), m_gpuCurrVertices, ScaleMode.ScaleToFit, false );
// }
//}
}
}