先介绍gltf的结构 创建java类
private Assets assets;
private Scene scene;
private ScenesList scenes;
private NodeListF node;
private MaterialsF materials;
private MeshesF meshes;
private AccessorsF accessorsF;
private BufferViewsF bufferViewsF;
private BuffersF buffersF;
每一个类再创造小类
1.Accessor
private int bufferView;
private int componentType;
private int count;
private List<Double> max;
private List<Double> min;
private String type;
2.Buff
private Integer byteLength;
private String uri;
3.BufferViews
private int buffer;
private int byteLength;
private int byteOffset;
private int target;
4.Material
private boolean doubleSided;
private String name;
private PbrMetallicRoughness pbrMetallicRoughness;
5.Mesh
private String name;
private List<Primitive> primitives;
6.Node
private int mesh;
private String name;
7.Scenes
private String name;
private NodeList nodes;
主函数
private static byte[] convertGltfToGlb(String gltfString,Gltf gltf) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// 解析GLTF字符串为JSON对象
JSONObject gltfJson = new JSONObject(gltfString);
// 提取所有的Buffers
JSONArray buffersArray = gltfJson.getJSONArray("buffers");
ByteArrayOutputStream combinedBufferStream = new ByteArrayOutputStream();
for (int i = 0; i < buffersArray.length(); i++) {
JSONObject bufferObj = buffersArray.getJSONObject(i);
String base64Buffer = bufferObj.getString("uri");
byte[] buffer = Base64.getDecoder().decode(base64Buffer.split(",")[1]);
combinedBufferStream.write(buffer);
bufferObj.remove("uri");
}
String str=gltf.toStringWithoutUri();
byte[] combinedBuffer = combinedBufferStream.toByteArray();
byte[] jsonBytes = gltf.toStringWithoutUri().getBytes(StandardCharsets.UTF_8);
// 写入GLB头部
outputStream.write("glTF".getBytes(StandardCharsets.UTF_8)); // Magic
outputStream.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(2).array()); // Version
// 占位符,稍后回填总长度
outputStream.write(new byte[4]);
// 写入JSON块长度和类型
int jsonLength = jsonBytes.length;
int jsonPadding = (4 - (jsonLength % 4)) % 4;
outputStream.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(jsonLength + jsonPadding ).array());
outputStream.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(0x4E4F534A).array()); // JSON块类型
outputStream.write(jsonBytes);
// 对齐到4字节
for (int i = 0; i < jsonPadding; i++) {
outputStream.write(0x20); // 使用空格进行填充
}
// 写入二进制块长度和类型
int binLength = combinedBuffer.length;
int binPadding = (4 - (binLength % 4)) % 4;
outputStream.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(binLength + binPadding ).array());
outputStream.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(0x004E4942).array()); // 二进制块类型
outputStream.write(combinedBuffer);
// 对齐到4字节
for (int i = 0; i < binPadding; i++) {
outputStream.write(0); // 使用0进行填充
}
// 回填总长度
byte[] glbBytes = outputStream.toByteArray();
ByteBuffer.wrap(glbBytes, 8, 4).order(ByteOrder.LITTLE_ENDIAN).putInt(glbBytes.length);
return glbBytes;
}
注意字节对齐其实很简单,可以先去了解下gltf和glb的格式标准,转换后的可以用glTF Viewer来检测是否成功