MMD中的VMD文件格式详解

MMD中的VMD文件格式详解

VMD是一个二进制流的文件。

Header

VMD有两个版本,你可以认为是v1跟v2。
前30个字节是版本描述。ASCII编码
v1是"Vocaloid Motion Data file"
v2是"Vocaloid Motion Data 0002"

接下来是名字,ShiftJIS编码
v1中是10个字节,v2中是20个字节

接下来每部分开头都是一个uint32_t,记录了这部分有多少关键帧。没有记录此项为0(而不是省略)。
然后跟上相应数量的记录。

类型 解释
byte*30 VersionInformation
byte*(10/20) ModelName
uint32_t BoneKeyFrameNumber
byte * 111 * n BoneKeyFrameRecord
uint32_t MorphKeyFrameNumber
byte* 47 *n MorphKeyFrameRecord
uint32_t CameraKeyFrameNumber
byte* 61 *n CameraKeyFrameRecord
uint32_t LightKeyFrameNumber
byte* 28 *n LightKeyFrameRecord

KeyFrameRecord

BoneKeyFrameRecord(byte*111)

类型 解释
byte*15(ShiftJIS) BoneName
uint32_t FrameTime
float*3 Translation.xyz
float*4 Rotation.xyzw
uint8_t*16 XCurve
uint8_t*16 YCurve
uint8_t*16 ZCurve
uint8_t*16 RCurve

uint8_t那里有冗余,每四个只读第一个就行。

MorphKeyFrameRecord(byte*47)

类型 解释
byte*15(ShiftJIS) MorphName
uint32_t FrameTime
float Weight

CameraKeyFrameRecord(byte*61)

类型 解释
uint32_t FrameTime
float Distance
float*3 Position.xyz
float*3 Rotation.xyz
uint8_t*24 Curve
float ViewAngle
uint8_t Orthographic

LightKeyFrameRecord(byte*28)

类型 解释
uint32_t FrameTime
float*3 Color.rgb
float*3 Direction.xyz

Java Code

package com.company;

import java.io.*;
import java.nio.ByteBuffer;

public class Main {

    public static void main(String[] args) {
        try {
            FileInputStream fis = new FileInputStream("test.vmd");
            BufferedInputStream bis = new BufferedInputStream(fis);
            DataInputStream dis = new DataInputStream(bis);

            String headerString = readString(dis, 30);

            int version = 0;
            String modelName = null;

            if (headerString.startsWith("Vocaloid Motion Data file")){
                version = 1;
                modelName = readString(dis, 10);
            }else if (headerString.startsWith("Vocaloid Motion Data 0002")){
                version = 2;
                modelName = readString(dis, 20);
            }else{
                throw new IOException("VmdReader: Not A VMD File!");
            }

            int numOfBoneRecord = readInt(dis);

            for (int i = 0; i < numOfBoneRecord; i++){

                String BoneRecordNameString = readString(dis, 15);

                int frameTime = readInt(dis);

                float tx = readFloat(dis);
                float ty = readFloat(dis);
                float tz = readFloat(dis);

                float rx = readFloat(dis);
                float ry = readFloat(dis);
                float rz = readFloat(dis);
                float rw = readFloat(dis);

                int txc1 = dis.readByte();
                dis.skipBytes(3);
                int txc2 = dis.readByte();
                dis.skipBytes(3);
                int txc3 = dis.readByte();
                dis.skipBytes(3);
                int txc4 = dis.readByte();
                dis.skipBytes(3);

                int tyc1 = dis.readByte();
                dis.skipBytes(3);
                int tyc2 = dis.readByte();
                dis.skipBytes(3);
                int tyc3 = dis.readByte();
                dis.skipBytes(3);
                int tyc4 = dis.readByte();
                dis.skipBytes(3);

                int tzc1 = dis.readByte();
                dis.skipBytes(3);
                int tzc2 = dis.readByte();
                dis.skipBytes(3);
                int tzc3 = dis.readByte();
                dis.skipBytes(3);
                int tzc4 = dis.readByte();
                dis.skipBytes(3);

                int rc1 = dis.readByte();
                dis.skipBytes(3);
                int rc2 = dis.readByte();
                dis.skipBytes(3);
                int rc3 = dis.readByte();
                dis.skipBytes(3);
                int rc4 = dis.readByte();
                dis.skipBytes(3);
            }
            int numOfMorphRecord = readInt(dis);
            for (int i = 0; i < numOfMorphRecord; i++){
                String name = readString(dis, 15);
                int frameTime = readInt(dis);
                float weight = readFloat(dis);
            }
            int numOfCameraRecord = readInt(dis);
            for (int i = 0; i < numOfCameraRecord; i++){
                int frameTime = readInt(dis);

                float distance = readFloat(dis);

                float px = readFloat(dis);
                float py = readFloat(dis);
                float pz = readFloat(dis);

                float rx = readFloat(dis);
                float ry = readFloat(dis);
                float rz = readFloat(dis);

                int txc1 = dis.readByte();
                int txc2 = dis.readByte();
                int txc3 = dis.readByte();
                int txc4 = dis.readByte();

                int tyc1 = dis.readByte();
                int tyc2 = dis.readByte();
                int tyc3 = dis.readByte();
                int tyc4 = dis.readByte();

                int tzc1 = dis.readByte();
                int tzc2 = dis.readByte();
                int tzc3 = dis.readByte();
                int tzc4 = dis.readByte();

                int qc1 = dis.readByte();
                int qc2 = dis.readByte();
                int qc3 = dis.readByte();
                int qc4 = dis.readByte();

                int dc1 = dis.readByte();
                int dc2 = dis.readByte();
                int dc3 = dis.readByte();
                int dc4 = dis.readByte();

                int vc1 = dis.readByte();
                int vc2 = dis.readByte();
                int vc3 = dis.readByte();
                int vc4 = dis.readByte();

                float viewAngle = readFloat(dis);
                byte orthographic = dis.readByte();

            }




        } catch (IOException e) {
            System.err.println(e);
            e.printStackTrace();
        }

    }

    private static int readInt(DataInputStream stream) throws IOException {
        byte intBytes[] = new byte[4];
        stream.read(intBytes);
        for (int j = 0; j < intBytes.length/2; j++){
            byte temp = intBytes[j];
            intBytes[j] = intBytes[intBytes.length -1 -j];
            intBytes[intBytes.length -1 -j] = temp;
        }
        return ByteBuffer.wrap(intBytes).getInt();
    }
    private static float readFloat(DataInputStream stream) throws IOException {
        byte floatBytes[] = new byte[4];
        stream.read(floatBytes);
        for (int j = 0; j < floatBytes.length/2; j++){
            byte temp = floatBytes[j];
            floatBytes[j] = floatBytes[floatBytes.length -1 -j];
            floatBytes[floatBytes.length -1 -j] = temp;
        }
        return ByteBuffer.wrap(floatBytes).getFloat();
    }

    private static String readString(DataInputStream stream, int length) throws IOException {
        byte[] name = new byte[length];
        stream.read(name);
        String nameString = new String(name, "Shift-jis");
        int indexOfNull = nameString.indexOf('\0');
        if (indexOfNull != -1){
            nameString = nameString.substring(0, indexOfNull);
        }
        return nameString;
    }
    private static String readString(DataInputStream stream, boolean utf8) throws IOException {
        int length = readInt(stream);
        byte[] name = new byte[length];
        stream.read(name);
        String string = null;
        if (utf8== false){
            for (int i = 0; i < name.length; i+=2){
                byte temp = name[i];
                name[i] = name[i+1];
                name[i+1] = temp;
            }
            string = new String(name, "utf-16");
        }else{
            string = new String(name, "utf-8");
        }
        return string;
    }
/*
    private static Vector2f readVector2f(DataInputStream stream) throws IOException {
        float x = readFloat(stream);
        float y = readFloat(stream);
        return new Vector3f(x,y);
    }

    private static Vector3f readVector3f(DataInputStream stream) throws IOException {
        float x = readFloat(stream);
        float y = readFloat(stream);
        float z = readFloat(stream);
        return new Vector3f(x,y,z);
    }
*/

}

猜你喜欢

转载自blog.csdn.net/haseetxwd/article/details/82821533
vmd