1#include "DualQuaternion_Common.hlsl"
2
3
4struct v2p
5{
6	float4 oPosition : SV_POSITION;
7	float2 oUv       : TEXCOORD0;
8	float4 colour    : COLOR;
9};
10
11struct dualQuaternionHardwareSkinningTwoWeights_vp_in
12{
13	float4 position : SV_POSITION;
14	float3 normal   : NORMAL;
15	float2 uv       : TEXCOORD0;
16	float4 blendIdx : BLENDINDICES;
17	float4 blendWgt : BLENDWEIGHT;
18};
19//Dual quaternion skinning with per-vertex antipodality handling (this is the most robust, but not the most efficient way):
20v2p dualQuaternionHardwareSkinningTwoWeights_vp(
21	dualQuaternionHardwareSkinningTwoWeights_vp_in input,
22	uniform float2x4 worldDualQuaternion2x4Array[24],
23	uniform float4x4 viewProjectionMatrix,
24	uniform float4   lightPos[2],
25	uniform float4   lightDiffuseColour[2],
26	uniform float4   ambient,
27	uniform float4   diffuse)
28{
29	v2p output;
30	float2x4 blendDQ = blendTwoWeightsAntipod(input.blendWgt, input.blendIdx, worldDualQuaternion2x4Array);
31
32	float len = length(blendDQ[0]);
33	blendDQ /= len;
34
35	float3 blendPosition = calculateBlendPosition(input.position.xyz, blendDQ);
36
37	//No need to normalize, the magnitude of the normal is preserved because only rotation is performed
38	float3 blendNormal = calculateBlendNormal(input.normal, blendDQ);
39
40	output.oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0));
41
42	// Lighting - support point and directional
43	float3 lightDir0 = normalize(lightPos[0].xyz - (blendPosition.xyz * lightPos[0].w));
44	float3 lightDir1 = normalize(lightPos[1].xyz - (blendPosition.xyz * lightPos[1].w));
45
46	output.oUv = input.uv;
47
48	output.colour = diffuse * (ambient + (saturate(dot(lightDir0, blendNormal)) * lightDiffuseColour[0]) +
49		(saturate(dot(lightDir1, blendNormal)) * lightDiffuseColour[1]));
50
51	return output;
52}
53
54struct dualQuaternionHardwareSkinningTwoWeightsCaster_vp_in
55{
56	float4 position : SV_POSITION;
57	float4 blendIdx : BLENDINDICES;
58	float4 blendWgt : BLENDWEIGHT;
59};
60
61struct v2ps
62{
63	float4 oPosition : SV_POSITION;
64	float4 colour    : COLOR;
65};
66//Shadow caster pass
67v2ps dualQuaternionHardwareSkinningTwoWeightsCaster_vp(
68	dualQuaternionHardwareSkinningTwoWeightsCaster_vp_in input,
69	uniform float2x4 worldDualQuaternion2x4Array[24],
70	uniform float4x4 viewProjectionMatrix,
71	uniform float4   ambient)
72{
73	v2ps output;
74	float2x4 blendDQ = blendTwoWeightsAntipod(input.blendWgt, input.blendIdx, worldDualQuaternion2x4Array);
75
76	float len = length(blendDQ[0]);
77	blendDQ /= len;
78
79	float3 blendPosition = calculateBlendPosition(input.position.xyz, blendDQ);
80
81	// view / projection
82	output.oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0));
83
84	output.colour = ambient;
85	return output;
86}
87
88//Two-phase skinning: dual quaternion skinning with scale and shear transformations
89v2p dualQuaternionHardwareSkinningTwoWeightsTwoPhase_vp(
90	dualQuaternionHardwareSkinningTwoWeights_vp_in input,
91	uniform float2x4 worldDualQuaternion2x4Array[24],
92	uniform float3x4 scaleM[24],
93	uniform float4x4 viewProjectionMatrix,
94	uniform float4   lightPos[2],
95	uniform float4   lightDiffuseColour[2],
96	uniform float4   ambient,
97	uniform float4   diffuse)
98{
99	v2p output;
100	//First phase - applies scaling and shearing:
101	float3x4 blendS = input.blendWgt.x*scaleM[input.blendIdx.x];
102	blendS += input.blendWgt.y*scaleM[input.blendIdx.y];
103
104	float3 pass1_position = mul(blendS, input.position);
105	float3x3 blendSrotAT = adjointTransposeMatrix(blendS);
106	float3 pass1_normal = normalize(mul(blendSrotAT, input.normal.xyz));
107
108	//Second phase
109	float2x4 blendDQ = blendTwoWeightsAntipod(input.blendWgt, input.blendIdx, worldDualQuaternion2x4Array);
110
111	float len = length(blendDQ[0]);
112	blendDQ /= len;
113
114	float3 blendPosition = calculateBlendPosition(pass1_position, blendDQ);
115
116	//No need to normalize, the magnitude of the normal is preserved because only rotation is performed
117	float3 blendNormal = calculateBlendNormal(pass1_normal, blendDQ);
118
119	output.oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0));
120
121	// Lighting - support point and directional
122	float3 lightDir0 = normalize(lightPos[0].xyz - (blendPosition.xyz * lightPos[0].w));
123	float3 lightDir1 = normalize(lightPos[1].xyz - (blendPosition.xyz * lightPos[1].w));
124
125	output.oUv = input.uv;
126	output.colour = diffuse * (ambient + (saturate(dot(lightDir0, blendNormal)) * lightDiffuseColour[0]) +
127		(saturate(dot(lightDir1, blendNormal)) * lightDiffuseColour[1]));
128	return output;
129}
130
131//Two-phase skinning shadow caster pass
132v2ps dualQuaternionHardwareSkinningTwoWeightsTwoPhaseCaster_vp(
133	dualQuaternionHardwareSkinningTwoWeightsCaster_vp_in input,
134	uniform float2x4 worldDualQuaternion2x4Array[24],
135	uniform float3x4 scaleM[24],
136	uniform float4x4 viewProjectionMatrix,
137	uniform float4   ambient)
138{
139	v2ps output;
140	//First phase - applies scaling and shearing:
141	float3x4 blendS = input.blendWgt.x*scaleM[input.blendIdx.x];
142	blendS += input.blendWgt.y*scaleM[input.blendIdx.y];
143
144	float3 pass1_position = mul(blendS, input.position);
145
146	//Second phase
147	float2x4 blendDQ = blendTwoWeightsAntipod(input.blendWgt, input.blendIdx, worldDualQuaternion2x4Array);
148
149	float len = length(blendDQ[0]);
150	blendDQ /= len;
151
152	float3 blendPosition = calculateBlendPosition(pass1_position, blendDQ);
153
154	// view / projection
155	output.oPosition = mul(viewProjectionMatrix, float4(blendPosition, 1.0));
156
157	output.colour = ambient;
158	return output;
159}
160
161