1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org
6
7 Copyright (c) 2000-2014 Torus Knot Software Ltd
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 THE SOFTWARE.
25 -----------------------------------------------------------------------------
26 */
27
28 #include "OgreShaderPrecompiledHeaders.h"
29
30 #ifdef RTSHADER_SYSTEM_BUILD_EXT_SHADERS
31 #define HS_DATA_BIND_NAME "HS_SRS_DATA"
32
33
34 namespace Ogre {
35
36 namespace RTShader {
37
38 /************************************************************************/
39 /* */
40 /************************************************************************/
DualQuaternionSkinning()41 DualQuaternionSkinning::DualQuaternionSkinning() : HardwareSkinningTechnique()
42 {
43 }
44
45 //-----------------------------------------------------------------------
resolveParameters(ProgramSet * programSet)46 bool DualQuaternionSkinning::resolveParameters(ProgramSet* programSet)
47 {
48 Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM);
49 Function* vsMain = vsProgram->getEntryPointFunction();
50
51 //if needed mark this vertex program as hardware skinned
52 if (mDoBoneCalculations == true)
53 {
54 vsProgram->setSkeletalAnimationIncluded(true);
55 }
56
57 //
58 // get the parameters we need whether we are doing bone calculations or not
59 //
60 // Note: in order to be consistent we will always output position, normal,
61 // tangent and binormal in both object and world space. And output position
62 // in projective space to cover the responsibility of the transform stage
63
64 //input param
65 mParamInPosition = vsMain->resolveInputParameter(Parameter::SPC_POSITION_OBJECT_SPACE);
66 mParamInNormal = vsMain->resolveInputParameter(Parameter::SPC_NORMAL_OBJECT_SPACE);
67 //mParamInBiNormal = vsMain->resolveInputParameter(Parameter::SPS_BINORMAL, 0, Parameter::SPC_BINORMAL_OBJECT_SPACE, GCT_FLOAT3);
68 //mParamInTangent = vsMain->resolveInputParameter(Parameter::SPS_TANGENT, 0, Parameter::SPC_TANGENT_OBJECT_SPACE, GCT_FLOAT3);
69
70 //local param
71 mParamLocalBlendPosition = vsMain->resolveLocalParameter("BlendedPosition", GCT_FLOAT3);
72 mParamLocalNormalWorld = vsMain->resolveLocalParameter(Parameter::SPC_NORMAL_WORLD_SPACE);
73 //mParamLocalTangentWorld = vsMain->resolveLocalParameter(Parameter::SPS_TANGENT, 0, Parameter::SPC_TANGENT_WORLD_SPACE, GCT_FLOAT3);
74 //mParamLocalBinormalWorld = vsMain->resolveLocalParameter(Parameter::SPS_BINORMAL, 0, Parameter::SPC_BINORMAL_WORLD_SPACE, GCT_FLOAT3);
75
76 //output param
77 mParamOutPositionProj = vsMain->resolveOutputParameter(Parameter::SPC_POSITION_PROJECTIVE_SPACE);
78
79 //check if parameter retrival went well
80 bool isValid =
81 (mParamInPosition.get() != NULL) &&
82 (mParamInNormal.get() != NULL) &&
83 //(mParamInBiNormal.get() != NULL) &&
84 //(mParamInTangent.get() != NULL) &&
85 (mParamLocalNormalWorld.get() != NULL) &&
86 //(mParamLocalTangentWorld.get() != NULL) &&
87 //(mParamLocalBinormalWorld.get() != NULL) &&
88 (mParamOutPositionProj.get() != NULL);
89
90
91 if (mDoBoneCalculations == true)
92 {
93 //input parameters
94 mParamInNormal = vsMain->resolveInputParameter(Parameter::SPC_NORMAL_OBJECT_SPACE);
95 //mParamInBiNormal = vsMain->resolveInputParameter(Parameter::SPS_BINORMAL, 0, Parameter::SPC_BINORMAL_OBJECT_SPACE, GCT_FLOAT3);
96 //mParamInTangent = vsMain->resolveInputParameter(Parameter::SPS_TANGENT, 0, Parameter::SPC_TANGENT_OBJECT_SPACE, GCT_FLOAT3);
97 mParamInIndices = vsMain->resolveInputParameter(Parameter::SPC_BLEND_INDICES);
98 mParamInWeights = vsMain->resolveInputParameter(Parameter::SPC_BLEND_WEIGHTS);
99 //ACT_WORLD_DUALQUATERNION_ARRAY_2x4 is an array of float4s, so there are two indices for each bone (required by Cg)
100 mParamInWorldMatrices = vsProgram->resolveAutoParameterInt(GpuProgramParameters::ACT_WORLD_DUALQUATERNION_ARRAY_2x4, GCT_FLOAT4, 0, mBoneCount * 2);
101 mParamInInvWorldMatrix = vsProgram->resolveParameter(GpuProgramParameters::ACT_INVERSE_WORLD_MATRIX);
102 mParamInViewProjMatrix = vsProgram->resolveParameter(GpuProgramParameters::ACT_VIEWPROJ_MATRIX);
103
104 mParamTempWorldMatrix = vsMain->resolveLocalParameter("worldMatrix", GCT_MATRIX_2X4);
105 mParamBlendDQ = vsMain->resolveLocalParameter("blendDQ", GCT_MATRIX_2X4);
106 mParamInitialDQ = vsMain->resolveLocalParameter("initialDQ", GCT_MATRIX_2X4);
107 mParamIndex1 = vsMain->resolveLocalParameter("index1", GCT_FLOAT1);
108 mParamIndex2 = vsMain->resolveLocalParameter("index2", GCT_FLOAT1);
109
110 if(mScalingShearingSupport)
111 {
112 if (ShaderGenerator::getSingleton().getTargetLanguage() == "hlsl")
113 {
114 //set hlsl shader to use row-major matrices instead of column-major.
115 //it enables the use of auto-bound 3x4 matrices in generated hlsl shader.
116 vsProgram->setUseColumnMajorMatrices(false);
117 }
118
119 mParamInScaleShearMatrices = vsProgram->resolveParameter(GpuProgramParameters::ACT_WORLD_SCALE_SHEAR_MATRIX_ARRAY_3x4, mBoneCount);
120 mParamBlendS = vsMain->resolveLocalParameter("blendS", GCT_MATRIX_3X4);
121 mParamTempFloat3x3 = vsMain->resolveLocalParameter("TempVal3x3", GCT_MATRIX_3X3);
122 mParamTempFloat3x4 = vsMain->resolveLocalParameter("TempVal3x4", GCT_MATRIX_3X4);
123 }
124
125 mParamTempFloat2x4 = vsMain->resolveLocalParameter("TempVal2x4", GCT_MATRIX_2X4);
126 mParamTempFloat4 = vsMain->resolveLocalParameter("TempVal4", GCT_FLOAT4);
127 mParamTempFloat3 = vsMain->resolveLocalParameter("TempVal3", GCT_FLOAT3);
128
129 //check if parameter retrival went well
130 isValid &=
131 (mParamInIndices.get() != NULL) &&
132 (mParamInWeights.get() != NULL) &&
133 (mParamInWorldMatrices.get() != NULL) &&
134 (mParamInViewProjMatrix.get() != NULL) &&
135 (mParamInInvWorldMatrix.get() != NULL) &&
136 (mParamBlendDQ.get() != NULL) &&
137 (mParamInitialDQ.get() != NULL) &&
138 (mParamIndex1.get() != NULL) &&
139 (mParamIndex2.get() != NULL) &&
140
141 (!mScalingShearingSupport || (mScalingShearingSupport &&
142 (mParamInScaleShearMatrices.get() != NULL &&
143 mParamBlendS.get() != NULL &&
144 mParamTempFloat3x3.get() != NULL &&
145 mParamTempFloat3x4.get() != NULL))) &&
146
147 (mParamTempFloat2x4.get() != NULL) &&
148 (mParamTempFloat4.get() != NULL) &&
149 (mParamTempFloat3.get() != NULL);
150 }
151 else
152 {
153 mParamInWorldMatrix = vsProgram->resolveParameter(GpuProgramParameters::ACT_WORLD_MATRIX);
154 mParamInWorldViewProjMatrix = vsProgram->resolveParameter(GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
155
156 //check if parameter retrival went well
157 isValid &=
158 (mParamInWorldMatrix.get() != NULL) &&
159 (mParamInWorldViewProjMatrix.get() != NULL);
160 }
161 return isValid;
162 }
163
164 //-----------------------------------------------------------------------
resolveDependencies(ProgramSet * programSet)165 bool DualQuaternionSkinning::resolveDependencies(ProgramSet* programSet)
166 {
167 Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM);
168 vsProgram->addDependency(FFP_LIB_COMMON);
169 vsProgram->addDependency(FFP_LIB_TRANSFORM);
170 vsProgram->addDependency(SGX_LIB_DUAL_QUATERNION);
171
172 return true;
173 }
174
175 //-----------------------------------------------------------------------
addFunctionInvocations(ProgramSet * programSet)176 bool DualQuaternionSkinning::addFunctionInvocations(ProgramSet* programSet)
177 {
178 Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM);
179 Function* vsMain = vsProgram->getEntryPointFunction();
180
181 //add functions to calculate position data in world, object and projective space
182 addPositionCalculations(vsMain);
183
184 //add functions to calculate normal and normal related data in world and object space
185 addNormalRelatedCalculations(vsMain, mParamInNormal, mParamLocalNormalWorld);
186 //addNormalRelatedCalculations(vsMain, mParamInTangent, mParamLocalTangentWorld, internalCounter);
187 //addNormalRelatedCalculations(vsMain, mParamInBiNormal, mParamLocalBinormalWorld, internalCounter);
188
189 return true;
190 }
191
192 //-----------------------------------------------------------------------
addPositionCalculations(Function * vsMain)193 void DualQuaternionSkinning::addPositionCalculations(Function* vsMain)
194 {
195 auto stage = vsMain->getStage(FFP_VS_TRANSFORM);
196
197 if (mDoBoneCalculations == true)
198 {
199 if(mScalingShearingSupport)
200 {
201 //Construct a scaling and shearing matrix based on the blend weights
202 for(int i = 0 ; i < getWeightCount() ; ++i)
203 {
204 //Assign the local param based on the current index of the scaling and shearing matrices
205 stage.assign({In(mParamInScaleShearMatrices), At(mParamInIndices).mask(indexToMask(i)),
206 Out(mParamTempFloat3x4)});
207
208 //Calculate the resultant scaling and shearing matrix based on the weights given
209 addIndexedPositionWeight(vsMain, i, mParamTempFloat3x4, mParamTempFloat3x4, mParamBlendS);
210 }
211
212 //Transform the position based by the scaling and shearing matrix
213 stage.callFunction(FFP_FUNC_TRANSFORM, mParamBlendS, In(mParamInPosition).xyz(), mParamLocalBlendPosition);
214 }
215 else
216 {
217 //Assign the input position to the local blended position
218 stage.assign(In(mParamInPosition).xyz(), mParamLocalBlendPosition);
219 }
220
221 //Set functions to calculate world position
222 for(int i = 0 ; i < getWeightCount() ; ++i)
223 {
224 //Set the index of the matrix
225 stage.assign(In(mParamInIndices).mask(indexToMask(i)), mParamIndex1);
226
227 //Multiply the index by 2
228 stage.callFunction(FFP_FUNC_MODULATE, mParamIndex1, 2, mParamIndex1);
229
230 //Add 1 to the index and assign as the second row's index
231 stage.callFunction(FFP_FUNC_ADD, mParamIndex1, 1, mParamIndex2);
232
233 //Build the dual quaternion matrix
234 stage.callFunction(SGX_FUNC_BUILD_DUAL_QUATERNION_MATRIX,
235 {In(mParamInWorldMatrices), At(mParamIndex1), In(mParamInWorldMatrices),
236 At(mParamIndex2), Out(mParamTempFloat2x4)});
237
238 //Adjust the podalities of the dual quaternions
239 if(mCorrectAntipodalityHandling)
240 {
241 adjustForCorrectAntipodality(vsMain, i, mParamTempFloat2x4);
242 }
243
244 //Calculate the resultant dual quaternion based on the weights given
245 addIndexedPositionWeight(vsMain, i, mParamTempFloat2x4, mParamTempFloat2x4, mParamBlendDQ);
246 }
247
248 //Normalize the dual quaternion
249 stage.callFunction(SGX_FUNC_NORMALIZE_DUAL_QUATERNION, mParamBlendDQ);
250
251 //Calculate the blend position
252 stage.callFunction(SGX_FUNC_CALCULATE_BLEND_POSITION, mParamLocalBlendPosition, mParamBlendDQ, mParamTempFloat4);
253
254 //Update from object to projective space
255 stage.callFunction(FFP_FUNC_TRANSFORM, mParamInViewProjMatrix, mParamTempFloat4, mParamOutPositionProj);
256 }
257 else
258 {
259 //update from object to projective space
260 stage.callFunction(FFP_FUNC_TRANSFORM, mParamInWorldViewProjMatrix, mParamInPosition, mParamOutPositionProj);
261 }
262 }
263
264 //-----------------------------------------------------------------------
addNormalRelatedCalculations(Function * vsMain,ParameterPtr & pNormalRelatedParam,ParameterPtr & pNormalWorldRelatedParam)265 void DualQuaternionSkinning::addNormalRelatedCalculations(Function* vsMain,
266 ParameterPtr& pNormalRelatedParam,
267 ParameterPtr& pNormalWorldRelatedParam)
268 {
269 auto stage = vsMain->getStage(FFP_VS_TRANSFORM);
270
271 if (mDoBoneCalculations == true)
272 {
273 if(mScalingShearingSupport)
274 {
275 //Calculate the adjoint transpose of the blended scaling and shearing matrix
276 stage.callFunction(SGX_FUNC_ADJOINT_TRANSPOSE_MATRIX, mParamBlendS, mParamTempFloat3x3);
277 //Transform the normal by the adjoint transpose of the blended scaling and shearing matrix
278 stage.callFunction(FFP_FUNC_TRANSFORM, mParamTempFloat3x3, pNormalRelatedParam, pNormalRelatedParam);
279 //Need to normalize again after transforming the normal
280 stage.callFunction(FFP_FUNC_NORMALIZE, pNormalRelatedParam);
281 }
282 //Transform the normal according to the dual quaternion
283 stage.callFunction(SGX_FUNC_CALCULATE_BLEND_NORMAL, pNormalRelatedParam, mParamBlendDQ, pNormalWorldRelatedParam);
284 //update back the original position relative to the object
285 stage.callFunction(FFP_FUNC_TRANSFORM, mParamInInvWorldMatrix, pNormalWorldRelatedParam, pNormalRelatedParam);
286 }
287 else
288 {
289 //update from object to world space
290 stage.callFunction(FFP_FUNC_TRANSFORM, mParamInWorldMatrix, pNormalRelatedParam, pNormalWorldRelatedParam);
291 }
292 }
293
294 //-----------------------------------------------------------------------
adjustForCorrectAntipodality(Function * vsMain,int index,const ParameterPtr & pTempWorldMatrix)295 void DualQuaternionSkinning::adjustForCorrectAntipodality(Function* vsMain,
296 int index, const ParameterPtr& pTempWorldMatrix)
297 {
298 auto stage = vsMain->getStage(FFP_VS_TRANSFORM);
299
300 //Antipodality doesn't need to be adjusted for dq0 on itself (used as the basis of antipodality calculations)
301 if(index > 0)
302 {
303 //This is the base dual quaternion dq0, which the antipodality calculations are based on
304 stage.callFunction(SGX_FUNC_ANTIPODALITY_ADJUSTMENT, mParamInitialDQ, mParamTempFloat2x4, pTempWorldMatrix);
305 }
306 else if(index == 0)
307 {
308 //Set the first dual quaternion as the initial dq
309 stage.assign(mParamTempFloat2x4, mParamInitialDQ);
310 }
311 }
312
313 //-----------------------------------------------------------------------
addIndexedPositionWeight(Function * vsMain,int index,ParameterPtr & pWorldMatrix,ParameterPtr & pPositionTempParameter,ParameterPtr & pPositionRelatedOutputParam)314 void DualQuaternionSkinning::addIndexedPositionWeight(Function* vsMain, int index,
315 ParameterPtr& pWorldMatrix, ParameterPtr& pPositionTempParameter,
316 ParameterPtr& pPositionRelatedOutputParam)
317 {
318 auto stage = vsMain->getStage(FFP_VS_TRANSFORM);
319
320 //multiply position with world matrix and put into temporary param
321 stage.callFunction(SGX_FUNC_BLEND_WEIGHT, In(mParamInWeights).mask(indexToMask(index)), pWorldMatrix,
322 pPositionTempParameter);
323
324 //check if on first iteration
325 if (index == 0)
326 {
327 //set the local param as the value of the world param
328 stage.assign(pPositionTempParameter, pPositionRelatedOutputParam);
329 }
330 else
331 {
332 //add the local param as the value of the world param
333 stage.callFunction(FFP_FUNC_ADD, pPositionTempParameter, pPositionRelatedOutputParam,
334 pPositionRelatedOutputParam);
335 }
336 }
337
338 }
339 }
340
341 #endif
342
343
344
345