Skinning.fxh 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. //////////////////////////////////////////////////////////////////////////////
  2. // ©2005 Electronic Arts Inc
  3. //
  4. // Definitions of functions and global variables for skinning
  5. //
  6. // Before including this header, define the number of bone matrices the shader
  7. // is to support. This is limited by the number of free vertex shader constant
  8. // registers.
  9. //
  10. // Declare this:
  11. //
  12. // static const int MaxSkinningBonesPerVertex = 2; // Number of bones per vertex supported (1 or 2)
  13. // static const int MaxSkinningBones = 64; // Number of bones supported
  14. //
  15. //////////////////////////////////////////////////////////////////////////////
  16. #ifndef _SKINNING_FXH_
  17. #define _SKINNING_FXH_
  18. #include "RegisterMap.fxh"
  19. //
  20. // Helper functions/structures
  21. //
  22. float3 MaybeNormalize(float3 direction)
  23. {
  24. // Normalization causes issues with HDR render targets that preserve floating point specials (eg on a Geforce7800).
  25. // At the moment we are not doing scaling, so the normals should be ok usually.
  26. // If we do scaling again, we will have to implement a "safe normalize" for some hardware,
  27. // sth equivalent to: return normalize(direction);
  28. return direction;
  29. }
  30. float3 Quaternion_RotateVector(float4 rotation, float3 position)
  31. {
  32. /* float x = rotation.w * position.x + rotation.y * position.z - rotation.z * position.y;
  33. float y = rotation.w * position.y + rotation.z * position.x - rotation.x * position.z;
  34. float z = rotation.w * position.z + rotation.x * position.y - rotation.y * position.x;
  35. float w = -(rotation.x * position.x + rotation.y * position.y) - rotation.z * position.z;
  36. float3 outPosition;
  37. outPosition.x = rotation.w * x - w * rotation.x + rotation.y * z - y * rotation.z;
  38. outPosition.y = rotation.w * y - w * rotation.y + rotation.z * x - z * rotation.x;
  39. outPosition.z = rotation.w * z - w * rotation.z + rotation.x * y - x * rotation.y;
  40. return outPosition;
  41. */
  42. float4 a;
  43. a = rotation.wwwx * position.xyzx + rotation.yzxy * position.zxyy;
  44. a.w = -a.w;
  45. a -= rotation.zxyz * position.yzxz;
  46. return rotation.www * a.xyz - rotation.xyz * a.www + rotation.yzx * a.zxy - rotation.zxy * a.yzx;
  47. }
  48. //
  49. // Definition of the BoneTransform struct with accessor functions
  50. //
  51. #define BoneTransform float4
  52. // struct BoneTransform;
  53. // {
  54. // float4 Rotation;
  55. // float4 Translation_Zero;
  56. // };
  57. float3 BoneTransformPosition(BoneTransform r, BoneTransform t, float3 position)
  58. {
  59. return Quaternion_RotateVector(r, position) + t.xyz;
  60. // return Quaternion_RotateVector(b.Rotation, position) + b.Translation_Zero.xyz;
  61. }
  62. float3 BoneTransformDirection(BoneTransform r, float3 direction)
  63. {
  64. return Quaternion_RotateVector(r, direction);
  65. // return Quaternion_RotateVector(b.Rotation, direction);
  66. }
  67. //
  68. // Global uploaded constants
  69. // Note: this will be declared in GlobalParameters.fxh when using indirect constants
  70. //
  71. int NumJointsPerVertex
  72. <
  73. string UIWidget = "None";
  74. string SasBindAddress = "Sas.Skeleton.NumJointsPerVertex";
  75. > = 0;
  76. #if defined(EA_PLATFORM_PS3)
  77. float4x3 World : World;
  78. #else
  79. float4x3 World : World : REGISTER_EVAL_VS(REGISTER_NON_SKINNING_WORLD_MATRIX_FIRST);
  80. #endif
  81. // Declare the bone transformation,
  82. // Note: we don't need to declare this to be in global parameters since the shader should upload these when it's needed
  83. // and these are not supposed to shared across shaders.
  84. #if !defined(USE_INDIRECT_CONSTANT)
  85. BoneTransform WorldBones[MaxSkinningBones*2]
  86. <
  87. string UIWidget = "None";
  88. string SasBindAddress = "Sas.Skeleton.MeshToJointToWorld[*]";
  89. >;
  90. #endif
  91. //
  92. // Functions/structs for calculating the skinning with multiple bones, but without tangent frame
  93. //
  94. struct VSInputSkinningMultipleBones
  95. {
  96. float3 Position[MaxSkinningBonesPerVertex] : POSITION;
  97. float3 Normal[MaxSkinningBonesPerVertex] : NORMAL;
  98. float2 BlendIndices : BLENDINDICES;
  99. float2 BlendWeights : BLENDWEIGHT;
  100. };
  101. void CalculatePositionAndNormal(VSInputSkinningMultipleBones InSkin, int NumJointsPerVertex,
  102. out float3 WorldPosition, out float3 WorldNormal)
  103. {
  104. if (NumJointsPerVertex == 2)
  105. {
  106. int index = (int)InSkin.BlendIndices.x * 2;
  107. WorldPosition = BoneTransformPosition(WorldBones[index], WorldBones[index+1], InSkin.Position[0]) * InSkin.BlendWeights.x;
  108. WorldNormal = BoneTransformDirection(WorldBones[index], InSkin.Normal[0]) * InSkin.BlendWeights.x;
  109. // Calculate for the second bone. Like above except stored in the y part of the variables.
  110. index = (int)InSkin.BlendIndices.y * 2;
  111. WorldPosition += BoneTransformPosition(WorldBones[index], WorldBones[index+1], InSkin.Position[1]) * InSkin.BlendWeights.y;
  112. WorldNormal += BoneTransformDirection(WorldBones[index], InSkin.Normal[1]) * InSkin.BlendWeights.y;
  113. // Normalize after the calculations.
  114. WorldNormal = MaybeNormalize(WorldNormal);
  115. }
  116. else if (NumJointsPerVertex == 1)
  117. {
  118. float boneIndex = InSkin.BlendIndices.x;
  119. int index = (int)boneIndex;
  120. index *= 2;
  121. WorldPosition = BoneTransformPosition(WorldBones[index], WorldBones[index+1], InSkin.Position[0]);
  122. WorldNormal = MaybeNormalize(BoneTransformDirection(WorldBones[index], InSkin.Normal[0]));
  123. }
  124. else
  125. {
  126. WorldPosition = mul(float4(InSkin.Position[0], 1), World);
  127. WorldNormal = MaybeNormalize(mul(InSkin.Normal[0], (float3x3)World));
  128. }
  129. }
  130. float GetOpacity(VSInputSkinningMultipleBones InSkin, int NumJointsPerVertex)
  131. {
  132. if (NumJointsPerVertex == 2)
  133. {
  134. int index = (int)InSkin.BlendIndices.x * 2;
  135. float visibility = WorldBones[index+1].w * InSkin.BlendWeights.x;
  136. index = (int)InSkin.BlendIndices.y * 2;
  137. visibility += WorldBones[index+1].w * InSkin.BlendWeights.y;
  138. return visibility;
  139. }
  140. else if (NumJointsPerVertex == 1)
  141. {
  142. float boneIndex = InSkin.BlendIndices.x;
  143. int index = (int)boneIndex;
  144. index *= 2;
  145. return WorldBones[index+1].w;
  146. }
  147. else
  148. {
  149. return 1.0;
  150. }
  151. }
  152. //
  153. // Functions/structs for calculating the skinning with just one, but with a tangent frame
  154. //
  155. struct VSInputSkinningOneBoneTangentFrame
  156. {
  157. float3 Position : POSITION;
  158. float3 Normal : NORMAL;
  159. float3 Tangent : TANGENT;
  160. float3 Binormal : BINORMAL;
  161. float BlendIndices : BLENDINDICES;
  162. };
  163. void CalculatePositionAndTangentFrame(VSInputSkinningOneBoneTangentFrame InSkin, int NumJointsPerVertex,
  164. out float3 WorldPosition, out float3 WorldNormal, out float3 WorldTangent, out float3 WorldBinormal)
  165. {
  166. if (NumJointsPerVertex > 0)
  167. {
  168. int index = InSkin.BlendIndices.x * 2;
  169. WorldPosition = BoneTransformPosition(WorldBones[index], WorldBones[index+1], InSkin.Position);
  170. WorldNormal = BoneTransformDirection(WorldBones[index], InSkin.Normal);
  171. WorldTangent = BoneTransformDirection(WorldBones[index], InSkin.Tangent);
  172. WorldBinormal = BoneTransformDirection(WorldBones[index], InSkin.Binormal);
  173. // Note: re-normalization skipped as quaternion-based BoneTransform can't do scaling anyway
  174. }
  175. else
  176. {
  177. WorldPosition = mul(float4(InSkin.Position, 1), World);
  178. WorldNormal = MaybeNormalize(mul(InSkin.Normal, (float3x3)World));
  179. WorldTangent = MaybeNormalize(mul(InSkin.Tangent, (float3x3)World));
  180. WorldBinormal = MaybeNormalize(mul(InSkin.Binormal, (float3x3)World));
  181. }
  182. }
  183. float GetOpacity(VSInputSkinningOneBoneTangentFrame InSkin, int NumJointsPerVertex)
  184. {
  185. if (NumJointsPerVertex > 0)
  186. {
  187. float boneIndex = InSkin.BlendIndices.x;
  188. int index = (int)boneIndex;
  189. index *= 2;
  190. return WorldBones[index+1].w;
  191. }
  192. else
  193. {
  194. return 1.0;
  195. }
  196. }
  197. float3 GetFirstBonePosition(float BlendIndex, int NumJointsPerVertex)
  198. {
  199. if (NumJointsPerVertex > 0)
  200. {
  201. int index = BlendIndex * 2;
  202. return WorldBones[index+1].xyz;
  203. }
  204. else
  205. {
  206. return World[3];
  207. }
  208. }
  209. #endif // Include guard