float2x4 blendTwoWeights(float4 blendWgt, float4 blendIdx, float2x4 dualQuaternions[24]) { float2x4 blendDQ = blendWgt.x*dualQuaternions[blendIdx.x]; blendDQ += blendWgt.y*dualQuaternions[blendIdx.y]; return blendDQ; } float2x4 blendTwoWeightsAntipod(float4 blendWgt, float4 blendIdx, float2x4 dualQuaternions[24]) { float2x4 dq0 = dualQuaternions[blendIdx.x]; float2x4 dq1 = dualQuaternions[blendIdx.y]; //Accurate antipodality handling. For speed increase, remove the following line, //though, the results will only be valid for rotations less than 180 degrees. if (dot(dq0[0], dq1[0]) < 0.0) dq1 *= -1.0; float2x4 blendDQ = blendWgt.x*dq0; blendDQ += blendWgt.y*dq1; return blendDQ; } float2x4 blendThreeWeightsAntipod(float4 blendWgt, float4 blendIdx, float2x4 dualQuaternions[24]) { float2x4 dq0 = dualQuaternions[blendIdx.x]; float2x4 dq1 = dualQuaternions[blendIdx.y]; float2x4 dq2 = dualQuaternions[blendIdx.z]; //Accurate antipodality handling. For speed increase, remove the following line, //though, the results will only be valid for rotations less than 180 degrees. if (dot(dq0[0], dq1[0]) < 0.0) dq1 *= -1.0; if (dot(dq0[0], dq2[0]) < 0.0) dq2 *= -1.0; float2x4 blendDQ = blendWgt.x*dq0; blendDQ += blendWgt.y*dq1; blendDQ += blendWgt.z*dq2; return blendDQ; } float2x4 blendFourWeightsAntipod(float4 blendWgt, float4 blendIdx, float2x4 dualQuaternions[24]) { float2x4 dq0 = dualQuaternions[blendIdx.x]; float2x4 dq1 = dualQuaternions[blendIdx.y]; float2x4 dq2 = dualQuaternions[blendIdx.z]; float2x4 dq3 = dualQuaternions[blendIdx.w]; //Accurate antipodality handling. For speed increase, remove the following line, //though, the results will only be valid for rotations less than 180 degrees. if (dot(dq0[0], dq1[0]) < 0.0) dq1 *= -1.0; if (dot(dq0[0], dq2[0]) < 0.0) dq2 *= -1.0; if (dot(dq0[0], dq3[0]) < 0.0) dq3 *= -1.0; float2x4 blendDQ = blendWgt.x*dq0; blendDQ += blendWgt.y*dq1; blendDQ += blendWgt.z*dq2; blendDQ += blendWgt.w*dq3; return blendDQ; } float3 calculateBlendPosition(float4 position, float2x4 blendDQ) { float3 blendPosition = position.xyz + 2.0*cross(blendDQ[0].yzw, cross(blendDQ[0].yzw, position.xyz) + blendDQ[0].x*position.xyz); float3 trans = 2.0*(blendDQ[0].x*blendDQ[1].yzw - blendDQ[1].x*blendDQ[0].yzw + cross(blendDQ[0].yzw, blendDQ[1].yzw)); blendPosition += trans; return blendPosition; } float3 calculateBlendNormal(float3 normal, float2x4 blendDQ) { return normal + 2.0*cross(blendDQ[0].yzw, cross(blendDQ[0].yzw, normal) + blendDQ[0].x*normal); } float3x3 adjointTransposeMatrix(float3x3 M) { float3x3 atM; atM._m00 = M._m22 * M._m11 - M._m12 * M._m21; atM._m01 = M._m12 * M._m20 - M._m10 * M._m22; atM._m02 = M._m10 * M._m21 - M._m20 * M._m11; atM._m10 = M._m02 * M._m21 - M._m22 * M._m01; atM._m11 = M._m22 * M._m00 - M._m02 * M._m20; atM._m12 = M._m20 * M._m01 - M._m00 * M._m21; atM._m20 = M._m12 * M._m01 - M._m02 * M._m11; atM._m21 = M._m10 * M._m02 - M._m12 * M._m00; atM._m22 = M._m00 * M._m11 - M._m10 * M._m01; return atM; } void shadow_caster_dq_vs( float4 position : POSITION, out float4 oPosition : POSITION, out float2 oDepthInfo : TEXCOORD0, uniform float4x4 wvpMatrix) { // output position. oPosition = mul(wvpMatrix, position); // depth info for the fragment. oDepthInfo.x = oPosition.z; oDepthInfo.y = oPosition.w; } void shadow_caster_dq_ps( in float4 colour : COLOR, out float4 oColour : COLOR) { oColour = colour; } //Shadow caster pass void shadow_caster_dq_skinning_1weight_vs( float4 position : POSITION, float4 blendIdx : BLENDINDICES, float4 blendWgt : BLENDWEIGHT, out float4 oPosition : POSITION, 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 ambient) { float2x4 blendDQ = blendWgt.x * worldDualQuaternion2x4Array[blendIdx.x]; float len = length(blendDQ[0]); blendDQ /= len; float3 blendPosition = calculateBlendPosition(position, blendDQ); // view / projection oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0)); colour = ambient; } void shadow_caster_dq_skinning_2weight_vs( float4 position : POSITION, float4 blendIdx : BLENDINDICES, float4 blendWgt : BLENDWEIGHT, out float4 oPosition : POSITION, 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 ambient) { float2x4 blendDQ = blendTwoWeightsAntipod(blendWgt, blendIdx, worldDualQuaternion2x4Array); float len = length(blendDQ[0]); blendDQ /= len; float3 blendPosition = calculateBlendPosition(position, blendDQ); // view / projection oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0)); colour = ambient; } void shadow_caster_dq_skinning_3weight_vs( float4 position : POSITION, float4 blendIdx : BLENDINDICES, float4 blendWgt : BLENDWEIGHT, out float4 oPosition : POSITION, 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 ambient) { float2x4 blendDQ = blendThreeWeightsAntipod(blendWgt, blendIdx, worldDualQuaternion2x4Array); float len = length(blendDQ[0]); blendDQ /= len; float3 blendPosition = calculateBlendPosition(position, blendDQ); // view / projection oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0)); colour = ambient; } void shadow_caster_dq_skinning_4weight_vs( float4 position : POSITION, float4 blendIdx : BLENDINDICES, float4 blendWgt : BLENDWEIGHT, out float4 oPosition : POSITION, 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 ambient) { float2x4 blendDQ = blendFourWeightsAntipod(blendWgt, blendIdx, worldDualQuaternion2x4Array); float len = length(blendDQ[0]); blendDQ /= len; float3 blendPosition = calculateBlendPosition(position, blendDQ); // view / projection oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0)); colour = ambient; } //Two-phase skinning shadow caster pass void shadow_caster_dq_skinning_1weight_twophase_vs( float4 position : POSITION, float4 blendIdx : BLENDINDICES, float4 blendWgt : BLENDWEIGHT, out float4 oPosition : POSITION, 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 ambient) { //First phase - applies scaling and shearing: float3x4 blendS = blendWgt.x*scaleM[blendIdx.x]; float3 pass1_position = mul(blendS, position); //Second phase float2x4 blendDQ = blendWgt.x * worldDualQuaternion2x4Array[blendIdx.x]; float len = length(blendDQ[0]); blendDQ /= len; float3 blendPosition = calculateBlendPosition(float4(pass1_position, 1.0), blendDQ); // view / projection oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0)); colour = ambient; } //Two-phase skinning shadow caster pass void shadow_caster_dq_skinning_2weight_twophase_vs( float4 position : POSITION, float4 blendIdx : BLENDINDICES, float4 blendWgt : BLENDWEIGHT, out float4 oPosition : POSITION, 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 ambient) { //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); //Second phase float2x4 blendDQ = blendTwoWeightsAntipod(blendWgt, blendIdx, worldDualQuaternion2x4Array); float len = length(blendDQ[0]); blendDQ /= len; float3 blendPosition = calculateBlendPosition(float4(pass1_position, 1.0), blendDQ); // view / projection oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0)); colour = ambient; }