如何解决卡住了,尝试使用lwjgl
我跟随this online tutorial使用asimp导入模型并对它们进行动画处理。我能够使用他的方法为它们设置动画。
但是,没有插值。所以我用this code来调整我已经写的东西。我有插值的工作方式,但是模型都很奇怪。
我花了几个小时遍历代码的每一行,并比较了从薄矩阵代码到gitbooks代码中矩阵乘法的矩阵乘法。
我已经比较了骨骼和节点的偏移矩阵(这很混乱,我知道我只是想让它正常工作)我已经遍历了插值代码我已经遍历了转换骨骼的代码转换成矩阵。我已经检查了代码,以确保正确的骨骼转换位于相应的索引处(关键帧类的骨骼转换数组的索引是骨骼ID)。
一切似乎都是正确的,但我无法使其正确进行动画处理。我花了几个小时来检查所有代码,但对其中的每个部分如何结合以及应该如何工作有了深刻的了解。但是对于我的一生,我找不到我做错的事情。
public class AnimMeshesLoader_Test extends StaticmeshesLoader {
public static AnimGameItem_Test loadAnimGameItem(String resourcePath,String texturesDir) throws Exception {
return loadAnimGameItem(resourcePath,texturesDir,aiProcess_GenSmoothnormals
| aiProcess_JoinIdenticalVertices
| aiProcess_Triangulate
| aiProcess_FixInfacingnormals
| aiProcess_LimitBoneWeights);
}
public static AnimGameItem_Test loadAnimGameItem(String resourcePath,String texturesDir,int flags) throws Exception {
AIScene aiScene = aiImportFile(resourcePath,flags);
if(aiScene == null) {
throw new Exception("Error loading model");
}
int numMaterials = aiScene.mNumMaterials();
PointerBuffer aimaterials = aiScene.mMaterials();
List<Material> materials = new ArrayList<Material>();
for(int i = 0; i < numMaterials; i++) {
aimaterial aimaterial = aimaterial.create(aimaterials.get(i));
processMaterial(aimaterial,materials,texturesDir);
}
List<Bone> boneList = new ArrayList<Bone>();
int numMeshes = aiScene.mNumMeshes();
PointerBuffer aimeshes = aiScene.mMeshes();
Mesh[] meshes = new Mesh[numMeshes];
for(int i = 0; i < numMeshes; i++) {
aimesh aimesh = aimesh.create(aimeshes.get(i));
Mesh mesh = processMesh(aimesh,boneList);
meshes[i] = mesh;
}
AINode aiRootNode = aiScene.mRootNode();
Matrix4f roottransformation = AnimMeshesLoader_Test.toMatrix(aiRootNode.mTransformation());
Node_Test rootNode = processNodesHierarchy(aiRootNode,null);
Map<String,Animation_Test> animations = processAnimations(aiScene,boneList,rootNode,roottransformation);
AnimGameItem_Test item = new AnimGameItem_Test(meshes,animations,roottransformation);
return item;
}
private static Mesh processMesh(aimesh aimesh,List<Material> materials,List<Bone> boneList) {
List<Float> vertices = new ArrayList<Float>();
List<Float> textures = new ArrayList<>();
List<Float> normals = new ArrayList<>();
List<Integer> indices = new ArrayList<>();
List<Integer> boneIds = new ArrayList<>();
List<Float> weights = new ArrayList<>();
processvertices(aimesh,vertices);
processnormals(aimesh,normals);
processtextCoords(aimesh,textures);
processIndices(aimesh,indices);
processBones(aimesh,boneIds,weights);
// Texture coordinates may not have been populated. We need at least the empty slots
if ( textures.size() == 0) {
int numElements = (vertices.size() / 3) * 2;
for (int i=0; i<numElements; i++) {
textures.add(0.0f);
}
}
Mesh mesh = new Mesh(Utils.listToArray(vertices),Utils.listToArray(normals),Utils.listToArray(textures),Utils.listIntToArray(indices),Utils.listIntToArray(boneIds),Utils.listToArray(weights));
Material material;
int materialIdx = aimesh.mMaterialIndex();
if(materialIdx >= 0 && materialIdx < materials.size()) {
material = materials.get(materialIdx);
} else {
material = new Material();
}
mesh.setMaterial(material);
return mesh;
}
private static void processBones(aimesh aimesh,List<Bone> boneList,List<Integer> boneIds,List<Float> weights) {
Map<Integer,List<VertexWeight>> weightSet = new HashMap<Integer,List<VertexWeight>>();
int numBones = aimesh.mNumBones();
PointerBuffer aiBones = aimesh.mBones();
for(int i = 0; i < numBones; i++) {
AIBone aiBone = AIBone.create(aiBones.get(i));
int id = boneList.size();
Bone bone = new Bone(id,aiBone.mName().dataString(),toMatrix(aiBone.mOffsetMatrix()));
boneList.add(bone);
int numWeights = aiBone.mNumWeights();
AIVertexWeight.Buffer aiWeights = aiBone.mWeights();
for(int j = 0; j < numWeights; j++) {
AIVertexWeight aiWeight = aiWeights.get(j);
VertexWeight vw = new VertexWeight(bone.getBoneId(),aiWeight.mVertexId(),aiWeight.mWeight());
List<VertexWeight> vertexWeightList = weightSet.get(vw.getVertexId());
if(vertexWeightList == null) {
vertexWeightList = new ArrayList<VertexWeight>();
weightSet.put(vw.getVertexId(),vertexWeightList);
}
vertexWeightList.add(vw);
}
}
int numVertices = aimesh.mNumVertices();
for(int i = 0; i < numVertices; i++) {
List<VertexWeight> vertexWeightList = weightSet.get(i);
int size = vertexWeightList != null ? vertexWeightList.size() : 0;
for(int j = 0; j < Mesh.MAX_WEIGHTS; j++) {
if(j < size) {
VertexWeight vw = vertexWeightList.get(j);
weights.add(vw.getWeight());
boneIds.add(vw.getBoneId());
} else {
weights.add(0.0f);
boneIds.add(0);
}
}
}
}
private static Node_Test processNodesHierarchy(AINode aiNode,Node_Test parentNode) {
String nodeName = aiNode.mName().dataString();
Node_Test node = new Node_Test(nodeName,parentNode);
int numChildren = aiNode.mNumChildren();
PointerBuffer aiChildren = aiNode.mChildren();
for(int i = 0; i < numChildren; i++) {
AINode aiChildNode = AINode.create(aiChildren.get(i));
Node_Test childNode = processNodesHierarchy(aiChildNode,node);
node.addChild(childNode);
}
return node;
}
private static Map<String,Animation_Test> processAnimations(AIScene aiScene,Node_Test rootNode,Matrix4f roottransformation) {
Map<String,Animation_Test> animations = new HashMap<String,Animation_Test>();
//Process all animations
int numAnimations = aiScene.mNumAnimations();
PointerBuffer aiAnimations = aiScene.mAnimations();
for(int i = 0; i < numAnimations; i++) {
AIAnimation aiAnimation = AIAnimation.create(aiAnimations.get(i));
//Calculate transformation matrices for each node
int numChannels = aiAnimation.mNumChannels();
PointerBuffer aiChannels = aiAnimation.mChannels();
for(int j = 0; j < numChannels; j++) {
AINodeAnim aiNodeAnim = AINodeAnim.create(aiChannels.get(j));
String nodeName = aiNodeAnim.mNodeName().dataString();
Node_Test node = rootNode.findByName(nodeName);
buildTransformationMatrices(aiNodeAnim,node);
}
Keyframe[] keyframes = orderKeyframes(boneList,roottransformation);
Animation_Test animation = new Animation_Test(aiAnimation.mName().dataString(),keyframes,aiAnimation.mDuration());
animations.put(animation.getName(),animation);
}
return animations;
}
private static void buildTransformationMatrices(AINodeAnim aiNodeAnim,Node_Test node) {
int numFrames = aiNodeAnim.mNumPositionKeys();
AIVectorKey.Buffer positionKeys = aiNodeAnim.mPositionKeys();
AIVectorKey.Buffer scalingKeys = aiNodeAnim.mScalingKeys();
AIQuatKey.Buffer rotationKeys = aiNodeAnim.mRotationKeys();
for(int i = 0; i < numFrames; i++) {
AIVectorKey aiVecKey = positionKeys.get(i);
AIVector3D vec = aiVecKey.mValue();
AIQuatKey quatKey = rotationKeys.get(i);
AIQuaternion aiQuat = quatKey.mValue();
Quaternionf quat = new Quaternionf(aiQuat.x(),aiQuat.y(),aiQuat.z(),aiQuat.w());
if(i < aiNodeAnim.mNumScalingKeys()) {
aiVecKey = scalingKeys.get(i);
vec = aiVecKey.mValue();
}
double timeStamp = aiVecKey.mTime();
BoneTransformation boneTransformation = new BoneTransformation(new Vector3f(vec.x(),vec.y(),vec.z()),quat,new Vector3f(vec.x(),vec.z()));
node.addTransformation(boneTransformation);
node.addKeyTime(timeStamp);
}
}
private static Keyframe[] orderKeyframes(List<Bone> boneList,Matrix4f roottransformation) {
//.getAnimationFrames() might need to be tweaked
int numKeyframes = rootNode.getAnimationFrames();
Keyframe[] keyframeList = new Keyframe[numKeyframes];
for(int i = 0; i < numKeyframes; i++) {
Keyframe keyframe = new Keyframe();
keyframeList[i] = keyframe;
int numBones = boneList.size();
for(int j = 0; j < numBones; j++) {
Bone bone = boneList.get(j);
Node_Test node = rootNode.findByName(bone.getBoneName());
node.addBoneId(j);
node.addBoneOffsetMatrix(bone.getoffsetMatrix());
BoneTransformation boneTransformation = Node_Test.getBoneTransformation(node,i);
double keyTime = Node_Test.getKeyTime(node,i);
keyframe.setBoneTransformation(j,boneTransformation);
keyframe.setTimeStamp(keyTime);
}
}
return keyframeList;
}
private static Matrix4f toMatrix(aimatrix4x4 aimatrix4x4) {
Matrix4f result = new Matrix4f();
result.m00(aimatrix4x4.a1());
result.m10(aimatrix4x4.a2());
result.m20(aimatrix4x4.a3());
result.m30(aimatrix4x4.a4());
result.m01(aimatrix4x4.b1());
result.m11(aimatrix4x4.b2());
result.m21(aimatrix4x4.b3());
result.m31(aimatrix4x4.b4());
result.m02(aimatrix4x4.c1());
result.m12(aimatrix4x4.c2());
result.m22(aimatrix4x4.c3());
result.m32(aimatrix4x4.c4());
result.m03(aimatrix4x4.d1());
result.m13(aimatrix4x4.d2());
result.m23(aimatrix4x4.d3());
result.m33(aimatrix4x4.d4());
return result;
}
}
public class BoneTransformation {
private Vector3f position;
private Quaternionf rotation;
private Vector3f scaling;
public BoneTransformation(Vector3f position,Quaternionf rotation,Vector3f scaling) {
this.position = position;
this.rotation = rotation;
this.scaling = scaling;
}
protected static BoneTransformation interpolate(BoneTransformation frameA,BoneTransformation frameB,float progression) {
Vector3f pos = interpolate(frameA.getPosition(),frameB.getPosition(),progression);
Quaternionf rot = interpolate(frameA.getRotation(),frameB.getRotation(),progression);
Vector3f scale = interpolate(frameA.getScaling(),frameB.getScaling(),progression);
return new BoneTransformation(pos,rot,scale);
}
private static Vector3f interpolate(Vector3f start,Vector3f end,float progression) {
float x = start.x + (end.x - start.x) * progression;
float y = start.y + (end.y - start.y) * progression;
float z = start.z + (end.z - start.z) * progression;
return new Vector3f(x,y,z);
}
private static Quaternionf interpolate(Quaternionf start,Quaternionf end,float progression) {
Quaternionf result = new Quaternionf(0,1);
float dot = start.w * end.w + start.x * end.x + start.y * end.y + start.z * end.z;
float progressionI = 1.0f - progression;
if(dot < 0) {
result.w = progressionI * start.w + progression * -end.w;
result.x = progressionI * start.x + progression * -end.x;
result.y = progressionI * start.y + progression * -end.y;
result.z = progressionI * start.z + progression * -end.z;
} else {
result.w = progressionI * start.w + progression * end.w;
result.x = progressionI * start.x + progression * end.x;
result.y = progressionI * start.y + progression * end.y;
result.z = progressionI * start.z + progression * end.z;
}
result.normalize();
return result;
}
protected Matrix4f createLocalTransformation() {
Matrix4f matrix = new Matrix4f();
matrix.translate(position)
.rotate(rotation)
.scale(scaling);
return matrix;
}
public Vector3f getPosition() {
return position;
}
public Quaternionf getRotation() {
return rotation;
}
public Vector3f getScaling() {
return scaling;
}
}
public class Animator {
private final AnimGameItem_Test animGameItem;
private Animation_Test currentAnimation;
private AnimatedFrame currentAnimatedFrame;
private float animationTime;
public Animator(AnimGameItem_Test animGameItem) {
this.animGameItem = animGameItem;
}
public void doAnimation(Animation_Test animation) {
this.animationTime = 0.0f;
this.currentAnimation = animation;
}
public void update(float interval) {
if(currentAnimation == null) {
return;
}
increaseAnimationTime(interval);
//get current and next keyframe and interpolate between them
Map<Integer,Matrix4f> currentLocalPose = calculateCurrentAnimationPose();
Map<Integer,Matrix4f> currentGlobalPose = new HashMap<Integer,Matrix4f>();
buildGlobalPose(currentLocalPose,animGameItem.getRootNode(),animGameItem.getRootNodeTransformation(),currentGlobalPose);
//buildGlobalPose(currentLocalPose,new Matrix4f(),currentGlobalPose);
currentAnimatedFrame = buildAnimatedFrame(currentGlobalPose);
}
private Map<Integer,Matrix4f> calculateCurrentAnimationPose() {
Keyframe[] keyframes = getPrevIoUsAndNextKeyframes();
float progression = calculateProgression(keyframes[0],keyframes[1]);
return interpolatePoses(keyframes[0],keyframes[1],progression);
}
private Keyframe[] getPrevIoUsAndNextKeyframes() {
Keyframe[] allKeyframes = currentAnimation.getKeyframes();
Keyframe prevIoUsKeyframe = allKeyframes[0];
Keyframe nextKeyframe = allKeyframes[0];
for(int i = 1; i < allKeyframes.length; i++) {
nextKeyframe = allKeyframes[i];
if(nextKeyframe.getTimeStamp() > animationTime) {
break;
}
prevIoUsKeyframe = allKeyframes[i];
}
return new Keyframe[] { prevIoUsKeyframe,nextKeyframe };
}
private void increaseAnimationTime(float interval) {
animationTime += interval;
if(animationTime > (float)currentAnimation.getDuration()) {
this.animationTime %= currentAnimation.getDuration();
}
}
private float calculateProgression(Keyframe prevIoUsKeyframe,Keyframe nextKeyframe) {
float totalTime = nextKeyframe.getTimeStamp() - prevIoUsKeyframe.getTimeStamp();
float currentTime = animationTime - prevIoUsKeyframe.getTimeStamp();
return currentTime / totalTime;
}
private Map<Integer,Matrix4f> interpolatePoses(Keyframe prevIoUsKeyframe,Keyframe nextKeyframe,float progression) {
Map<Integer,Matrix4f> currentLocalPose = new HashMap<Integer,Matrix4f>();
for(int i = 0; i < prevIoUsKeyframe.getBoneTransformations().length; i++) {
BoneTransformation prevIoUsBoneTransformation = prevIoUsKeyframe.getBoneTransformations()[i];
BoneTransformation nextBoneTransformation = nextKeyframe.getBoneTransformations()[i];
BoneTransformation currentBoneTransformation = BoneTransformation.interpolate(prevIoUsBoneTransformation,nextBoneTransformation,progression);
currentLocalPose.put(i,currentBoneTransformation.createLocalTransformation());
}
return currentLocalPose;
}
private void buildGlobalPose(Map<Integer,Matrix4f> currentLocalPose,Node_Test node,Matrix4f parentTransformation,Map<Integer,Matrix4f> globalPose) {
Matrix4f currentLocalTransformation = null;
Matrix4f currentGlobalTransformation = null;
if(node.getBoneId() != -1) {
currentLocalTransformation = currentLocalPose.get(node.getBoneId());
currentGlobalTransformation = parentTransformation.mul(currentLocalTransformation);
} else {
currentGlobalTransformation = parentTransformation;
}
for(Node_Test childNode : node.getChildren()) {
buildGlobalPose(currentLocalPose,childNode,new Matrix4f(currentGlobalTransformation),globalPose);
}
if(node.getBoneId() != -1) {
currentGlobalTransformation = currentGlobalTransformation.mul(node.getBoneOffsetMatrix());
globalPose.put(node.getBoneId(),currentGlobalTransformation);
}
}
private AnimatedFrame buildAnimatedFrame(Map<Integer,Matrix4f> currentGlobalPose) {
AnimatedFrame animatedFrame = new AnimatedFrame();
for(Map.Entry<Integer,Matrix4f> matrixEntry : currentGlobalPose.entrySet()) {
int boneId = matrixEntry.getKey();
Matrix4f matrix = matrixEntry.getValue();
animatedFrame.setMatrix(boneId,matrix);
}
return animatedFrame;
}
public AnimatedFrame getCurrentAnimatedFrame() {
return currentAnimatedFrame;
}
private Matrix4f copyMatrix(Matrix4f source) {
Matrix4f matrix = new Matrix4f();
matrix.m00(source.m00());
matrix.m01(source.m01());
matrix.m02(source.m02());
matrix.m03(source.m03());
matrix.m10(source.m10());
matrix.m11(source.m11());
matrix.m12(source.m12());
matrix.m13(source.m13());
matrix.m20(source.m20());
matrix.m21(source.m21());
matrix.m22(source.m22());
matrix.m23(source.m23());
matrix.m30(source.m30());
matrix.m31(source.m31());
matrix.m32(source.m32());
matrix.m33(source.m33());
return matrix;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。