#include "DualQuaternionSkinning_Shadow.cg" //Dual quaternion skinning with per-vertex antipodality handling (this is the most robust, but not the most efficient way): void dualQuaternionHardwareSkinningTwoWeights_vp( float4 position : POSITION, float3 normal : NORMAL, float2 uv : TEXCOORD0, float4 blendIdx : BLENDINDICES, float4 blendWgt : BLENDWEIGHT, out float4 oPosition : POSITION, out float2 oUv : TEXCOORD0, out float4 colour : COLOR, // Support up to 24 bones of float3x4 // vs_1_1 only supports 96 params so more than this is not feasible uniform float2x4 worldDualQuaternion2x4Array[24], uniform float4x4 viewProjectionMatrix, uniform float4 lightPos[2], uniform float4 lightDiffuseColour[2], uniform float4 ambient, uniform float4 diffuse) { float2x4 blendDQ = blendTwoWeightsAntipod(blendWgt, blendIdx, worldDualQuaternion2x4Array); float len = length(blendDQ[0]); blendDQ /= len; float3 blendPosition = calculateBlendPosition(position, blendDQ); //No need to normalize, the magnitude of the normal is preserved because only rotation is performed float3 blendNormal = calculateBlendNormal(normal, blendDQ); oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0)); // Lighting - support point and directional float3 lightDir0 = normalize(lightPos[0].xyz - (blendPosition.xyz * lightPos[0].w)); float3 lightDir1 = normalize(lightPos[1].xyz - (blendPosition.xyz * lightPos[1].w)); oUv = uv; colour = diffuse * (ambient + (saturate(dot(lightDir0, blendNormal)) * lightDiffuseColour[0]) + (saturate(dot(lightDir1, blendNormal)) * lightDiffuseColour[1])); } //Two-phase skinning: dual quaternion skinning with scale and shear transformations void dualQuaternionHardwareSkinningTwoWeightsTwoPhase_vp( float4 position : POSITION, float3 normal : NORMAL, float2 uv : TEXCOORD0, float4 blendIdx : BLENDINDICES, float4 blendWgt : BLENDWEIGHT, out float4 oPosition : POSITION, out float2 oUv : TEXCOORD0, out float4 colour : COLOR, // Support up to 24 bones of float3x4 // vs_1_1 only supports 96 params so more than this is not feasible uniform float2x4 worldDualQuaternion2x4Array[24], uniform float3x4 scaleM[24], uniform float4x4 viewProjectionMatrix, uniform float4 lightPos[2], uniform float4 lightDiffuseColour[2], uniform float4 ambient, uniform float4 diffuse) { //First phase - applies scaling and shearing: float3x4 blendS = blendWgt.x*scaleM[blendIdx.x]; blendS += blendWgt.y*scaleM[blendIdx.y]; float3 pass1_position = mul(blendS, position); float3x3 blendSrotAT = adjointTransposeMatrix(float3x3(blendS)); float3 pass1_normal = normalize(mul(blendSrotAT, normal.xyz)); //Second phase float2x4 blendDQ = blendTwoWeightsAntipod(blendWgt, blendIdx, worldDualQuaternion2x4Array); float len = length(blendDQ[0]); blendDQ /= len; float3 blendPosition = calculateBlendPosition(float4(pass1_position, 1.0), blendDQ); //No need to normalize, the magnitude of the normal is preserved because only rotation is performed float3 blendNormal = calculateBlendNormal(pass1_normal, blendDQ); oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0)); // Lighting - support point and directional float3 lightDir0 = normalize(lightPos[0].xyz - (blendPosition.xyz * lightPos[0].w)); float3 lightDir1 = normalize(lightPos[1].xyz - (blendPosition.xyz * lightPos[1].w)); oUv = uv; colour = diffuse * (ambient + (saturate(dot(lightDir0, blendNormal)) * lightDiffuseColour[0]) + (saturate(dot(lightDir1, blendNormal)) * lightDiffuseColour[1])); }