我正在用WebGL编写一个小游戏来帮助自己理解3D游戏编程中的一些核心概念(不使用现有的引擎)。这个项目就是我在业余时间进行的事情,如果我觉得有必要,那么WebGL版本将成为原型程序的第二个原型。
我目前正处于试图为角色模型制作动画的阶段,并且几天来一直在努力弄清楚它应该如何完成。我发现很难在网上找到任何简单的教程(或者甚至从另一种编程语言翻译),所以我来到这个网站寻求一些指导。如果问题可以在这里得到解决,我希望它能帮助其他人在将来对这个概念提出类似的问题。
我目前的解决方案是这个(对于模型中的每个骨骼):
这是到目前为止计算模型矩阵的相关代码。我知道代码不是通过每帧为每个骨骼创建大量新矩阵而完全有效,但我已经这样写了它以便我能够理解它。稍后优化。指示旋转的唯一骨骼是标记为“Bip01 L UpperArm”的骨骼,即右肩角色。
var temp = 0.0;
ModelInstance.prototype.Tick = function(step, name, hasArmature, bones) {
temp -= 0.0001*step;
if(temp>1.0)
temp -= 2.0;
else if(temp<-1.0)
temp += 2.0;
// Calculate world matrix for overall model
var rotation = quat.fromValues(this.rX, this.rY, this.rZ, 1.0);
quat.calculateW(rotation, rotation);
mat4.fromRotationTranslation(this.worldMatrix, rotation, [this.x, this.y, this.z]);
mat4.scale(this.worldMatrix, this.worldMatrix, [this.sX, this.sY, this.sZ]);
mat4.transpose(this.worldMatrix, this.worldMatrix);
// Calculate bone matrices
if(hasArmature) {
for(var i=0; i<bones.length && i<40; i++) {
// Rotate just the right shoulder for this example
var boneRotate = bones[i].name == "Bip01 L UpperArm" ? quat.fromValues(0.0, 0.0, temp, 1.0) : quat.fromValues(0.0, 0.0, 0.0, 1.0);
quat.calculateW(boneRotate, boneRotate);
// Original Position
// Translate to the position of the bone
var translationMatrix = mat4.create();
mat4.translate(translationMatrix, translationMatrix, [bones[i].pos[0], bones[i].pos[1], bones[i].pos[2]]);
// Rotation Matrix
// Amount to rotate the bone by
var rotationMatrix = mat4.create();
mat4.fromQuat(rotationMatrix, boneRotate);
// New Position
// Rotate the bone around the bones origin by the requested amount
var boneMatrix = mat4.create();
mat4.multiply(boneMatrix, translationMatrix, rotationMatrix);
// Apply parent transformations
if(bones[i].parent>=0) {
var parentID = bones[i].parent;
while(parentID>=0) {
mat4.multiply(boneMatrix, boneMatrix, this.boneMatrices[parentID]);
parentID = bones[parentID].parent;
}
}
// Remove original translation
var inverseMatrix = mat4.create();
mat4.invert(inverseMatrix, translationMatrix);
mat4.multiply(boneMatrix, boneMatrix, inverseMatrix);
// Save matrix
this.boneMatrices[i] = boneMatrix;
}
}
}
一些相关骨骼数据如下所示:
{
"name":"Bip01",
"parent":-1,
"pos":[0.00000000,2.48177004,0.03703270]
},
/*....*/
{
"name":"Bip01 Pelvis",
"parent":0,
"pos":[0.00000000,2.48177004,0.03141975]
},
{
"name":"Bip01 Spine",
"parent":2,
"pos":[0.00000000,2.73970008,0.03122885]
},
{
"name":"Bip01 Spine1",
"parent":3,
"pos":[0.00000000,2.97957993,0.03618195]
},
{
"name":"Bip01 Neck",
"parent":4,
"pos":[0.00000000,3.83638000,0.00980067]
}
/*....*/
{
"name":"Bip01 L Clavicle",
"parent":5,
"pos":[0.07849900,3.83639002,0.00993846]
},
{
"name":"Bip01 L UpperArm",
"parent":10,
"pos":[0.47621104,3.63395000,-0.04814709]
},
{
"name":"Bip01 L Forearm",
"parent":11,
"pos":[0.93108791,3.14579010,-0.13482325]
},
{
"name":"Bip01 L Hand",
"parent":12,
"pos":[1.32678998,2.72037005,-0.01493155]
}
/*....*/
最后,顶点着色器的相关部分如下所示:
mat4 skinMatrix;
skinMatrix = uBoneMatrices[int(aBoneIndex.x)] * aBoneWeight.x +
uBoneMatrices[int(aBoneIndex.y)] * aBoneWeight.y +
uBoneMatrices[int(aBoneIndex.z)] * aBoneWeight.z +
uBoneMatrices[int(aBoneIndex.w)] * aBoneWeight.w;
gl_Position = (((vec4(aPosition, 1.0) * skinMatrix) * uWMatrix) * uVMatrix) * uPMatrix;
vLightViewPosition = (((vec4(aPosition, 1.0) * skinMatrix) * uWMatrix) * uLVMatrix) * uLPMatrix;
这是我目前关于如何解决它的想法以及基于上面代码的当前结果的图像。正如你所看到的,手向右延伸到模型脚(只记住肩部实际上是在旋转),所以我假设我写的解决方案存在问题。
感谢任何帮助:)
使用的实用程序:glMatrix