/** * Constructor. Creates the basic set of bone's data. * * @param boneStructure the bone's structure * @param parent bone's parent (null if the bone is the root bone) * @param objectToArmatureMatrix object-to-armature transformation matrix * @param bonesPoseChannels a map of pose channels for each bone OMA * @param blenderContext the blender context * @throws BlenderFileException an exception is thrown when problem with blender data reading * occurs */ private BoneContext( Structure boneStructure, BoneContext parent, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { this.parent = parent; this.boneStructure = boneStructure; boneName = boneStructure.getFieldValue("name").toString(); ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); armatureMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", true); fixUpAxis = blenderContext.getBlenderKey().isFixUpAxis(); this.computeRestMatrix(objectToArmatureMatrix); List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext); for (Structure child : childbase) { this.children.add( new BoneContext(child, this, objectToArmatureMatrix, bonesPoseChannels, blenderContext)); } poseChannel = bonesPoseChannels.get(boneStructure.getOldMemoryAddress()); blenderContext.setBoneContext(boneStructure.getOldMemoryAddress(), this); }
@Override public void performBakingOperation() { Bone owner = blenderContext.getBoneContext(ownerOMA).getBone(); Bone target = null; if (targetArmatureOMA != null) { // first make sure the target is loaded ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); try { objectHelper.toObject( (Structure) blenderContext.getLoadedFeature( targetArmatureOMA, LoadedFeatureDataType.LOADED_STRUCTURE), blenderContext); } catch (BlenderFileException e) { LOGGER.warning( "Problems occured during target object loading. The constraint " + name + " will not be applied."); return; } BoneContext boneContext = blenderContext.getBoneByName(subtargetName); target = boneContext.getBone(); this.targetOMA = boneContext.getBoneOma(); } this.prepareTracksForApplyingConstraints(); AnimData animData = blenderContext.getAnimData(ownerOMA); if (animData != null) { for (Animation animation : animData.anims) { Transform ownerTransform = constraintHelper.getBoneTransform(ownerSpace, owner); Transform targetTransform = target != null ? constraintHelper.getBoneTransform(targetSpace, target) : null; BoneTrack boneTrack = constraintHelper.getTrack(owner, animData.skeleton, animation); BoneTrack targetTrack = target != null ? constraintHelper.getTrack(target, animData.skeleton, animation) : null; constraintDefinition.bake( ownerTransform, targetTransform, boneTrack, targetTrack, this.ipo); } } }
/** * This method builds the bone. It recursively builds the bone's children. * * @param bones a list of bones where the newly created bone will be added * @param boneOMAs the map between bone and its old memory address * @param blenderContext the blender context * @return newly created bone */ public Bone buildBone(List<Bone> bones, Map<Bone, Long> boneOMAs, BlenderContext blenderContext) { Long boneOMA = boneStructure.getOldMemoryAddress(); bone = new Bone(boneName); bones.add(bone); boneOMAs.put(bone, boneOMA); blenderContext.addLoadedFeatures(boneOMA, boneName, boneStructure, bone); Matrix4f pose = this.restMatrix.clone(); ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); Vector3f poseLocation = pose.toTranslationVector(); Quaternion rotation = pose.toRotationQuat(); Vector3f scale = objectHelper.getScale(pose); bone.setBindTransforms(poseLocation, rotation, scale); for (BoneContext child : children) { bone.addChild(child.buildBone(bones, boneOMAs, blenderContext)); } this.computePoseTransform(); return bone; }
/** * This constructor reads animation data from the object structore. The stored data is the * AnimData and additional data is armature's OMA. * * @param objectStructure the structure of the object * @param modifierStructure the structure of the modifier * @param blenderContext the blender context * @throws BlenderFileException this exception is thrown when the blender file is somehow * corrupted */ public ArmatureModifier( Structure objectStructure, Structure modifierStructure, BlenderContext blenderContext) throws BlenderFileException { if (this.validate(modifierStructure, blenderContext)) { Pointer pArmatureObject = (Pointer) modifierStructure.getFieldValue("object"); if (pArmatureObject.isNotNull()) { ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); ArmatureHelper armatureHelper = blenderContext.getHelper(ArmatureHelper.class); Structure armatureObject = pArmatureObject.fetchData(blenderContext.getInputStream()).get(0); this.armatureObjectOMA = armatureObject.getOldMemoryAddress(); // read skeleton // changing bones matrices so that they fit the current object Structure armatureStructure = ((Pointer) armatureObject.getFieldValue("data")) .fetchData(blenderContext.getInputStream()) .get(0); Structure bonebase = (Structure) armatureStructure.getFieldValue("bonebase"); List<Structure> bonesStructures = bonebase.evaluateListBase(blenderContext); for (Structure boneStructure : bonesStructures) { BoneTransformationData rootBoneTransformationData = armatureHelper.readBoneAndItsChildren(boneStructure, null, blenderContext); armatureHelper.addBoneDataRoot(rootBoneTransformationData); } Matrix4f armatureObjectMatrix = objectHelper.getTransformationMatrix(armatureObject); Matrix4f inverseMeshObjectMatrix = objectHelper.getTransformationMatrix(objectStructure).invert(); Matrix4f additionalRootBoneTransformation = inverseMeshObjectMatrix.multLocal(armatureObjectMatrix); Bone[] bones = armatureHelper.buildBonesStructure(Long.valueOf(0L), additionalRootBoneTransformation); // read mesh indexes Structure meshStructure = ((Pointer) objectStructure.getFieldValue("data")) .fetchData(blenderContext.getInputStream()) .get(0); this.meshOMA = meshStructure.getOldMemoryAddress(); this.readVerticesWeightsData(objectStructure, meshStructure, blenderContext); // read animations ArrayList<Animation> animations = new ArrayList<Animation>(); List<FileBlockHeader> actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00)); if (actionHeaders != null) { // it may happen that the model has armature with no actions for (FileBlockHeader header : actionHeaders) { Structure actionStructure = header.getStructure(blenderContext); String actionName = actionStructure.getName(); BoneTrack[] tracks = armatureHelper.getTracks(actionStructure, blenderContext); // determining the animation time float maximumTrackLength = 0; for (BoneTrack track : tracks) { float length = track.getLength(); if (length > maximumTrackLength) { maximumTrackLength = length; } } Animation boneAnimation = new Animation(actionName, maximumTrackLength); boneAnimation.setTracks(tracks); animations.add(boneAnimation); } } animData = new AnimData(new Skeleton(bones), animations); } } }