loaders.gl
Version:
Framework-independent loaders for 3D graphics formats
279 lines (222 loc) • 8.77 kB
JavaScript
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the 'License');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/* eslint-disable no-console */
/* global console */
const draco3d = require('draco3d');
const assert = require('assert');
const DEFAULT_ENCODING_OPTIONS = {
speed: [5, 5],
method: 'MESH_EDGEBREAKER_ENCODING',
quantization: {
POSITION: 10
}
};
export default class DRACOEncoder {
constructor() {
this.encoderModule = draco3d.createEncoderModule({});
this.encoder = new this.encoderModule.Encoder();
}
destroy() {
this.this.encoderModule.destroy(this.encoder);
this.encoder = null;
this.encoderModule = null;
}
destroyEncodedObject(object) {
if (object) {
this.encoderModule.destroy(object);
}
}
// Set encoding options.
setOptions(opts) {
if ('speed' in opts) {
this.encoder.SetSpeedOptions(...opts.speed);
}
if ('method' in opts) {
this.encoder.SetEncodingMethod(this.encoderModule[opts.method]);
}
if ('quantization' in opts) {
for (const attribute in opts.quantization) {
const bits = opts.quantization[attribute];
this.encoder.SetAttributeQuantization(this.encoderModule[attribute], bits);
}
}
}
encodeCloud(mesh, decoder) {
const newMesh = this.prepareMesh(mesh, decoder);
this.setOptions(DEFAULT_ENCODING_OPTIONS);
// Encoding.
// console.log('Encoding...');
const encodedData = new this.encoderModule.DracoInt8Array();
const encodedLen = this.encoder.EncodeMeshToDracoBuffer(newMesh, encodedData);
this.encoderModule.destroy(newMesh);
if (!(encodedLen > 0)) {
throw new Error('Draco encoding failed.');
}
console.log(`Encoded size is ${encodedLen}`);
// Copy encoded data to buffer.
const outputBuffer = new ArrayBuffer(encodedLen);
const outputData = new Int8Array(outputBuffer);
for (let i = 0; i < encodedLen; ++i) {
outputData[i] = encodedData.GetValue(i);
}
this.encoderModule.destroy(encodedData);
return outputData;
}
encodeMesh(mesh, decoder) {
const newMesh = this.prepareMesh(mesh, decoder);
this.setOptions(DEFAULT_ENCODING_OPTIONS);
// Encoding.
// console.log('Encoding...');
const encodedData = new this.encoderModule.DracoInt8Array();
const encodedLen = this.encoder.EncodeMeshToDracoBuffer(newMesh, encodedData);
this.encoderModule.destroy(newMesh);
if (!(encodedLen > 0)) {
throw new Error('Draco encoding failed.');
}
console.log(`Encoded size is ${encodedLen}`);
// Copy encoded data to buffer.
const outputBuffer = new ArrayBuffer(encodedLen);
const outputData = new Int8Array(outputBuffer);
for (let i = 0; i < encodedLen; ++i) {
outputData[i] = encodedData.GetValue(i);
}
this.encoderModule.destroy(encodedData);
// this.encoderModule.destroy(meshBuilder);
return outputData;
}
prepareMesh(mesh, decoder) {
const numFaces = mesh.num_faces();
const numIndices = numFaces * 3;
const numPoints = mesh.num_points();
const indices = new Uint32Array(numIndices);
console.log(`Number of faces ${numFaces}`);
console.log(`Number of vertices ${numPoints}`);
const meshBuilder = new this.encoderModule.MeshBuilder();
// Add Faces to mesh
const integerArray = new this.decoderModule.DracoInt32Array();
for (let i = 0; i < numFaces; ++i) {
decoder.GetFaceFromMesh(mesh, i, integerArray);
const index = i * 3;
indices[index] = integerArray.GetValue(0);
indices[index + 1] = integerArray.GetValue(1);
indices[index + 2] = integerArray.GetValue(2);
}
this.decoderModule.destroy(integerArray);
// Create a mesh object for storing mesh data.
const newMesh = new this.encoderModule.Mesh();
meshBuilder.AddFacesToMesh(newMesh, numFaces, indices);
this._prepareMeshAttributes(mesh, newMesh, numPoints, meshBuilder, decoder);
this.encoderModule.destroy(meshBuilder);
return newMesh;
}
_prepareMeshAttributes(mesh, newMesh, numPoints, meshBuilder, decoder) {
const attrs = {POSITION: 3, NORMAL: 3, COLOR: 3, TEX_COORD: 2};
Object.keys(attrs).forEach((attr) => {
const stride = attrs[attr];
const numValues = numPoints * stride;
const decoderAttr = this.decoderModule[attr];
const encoderAttr = this.encoderModule[attr];
const attrId = decoder.GetAttributeId(mesh, decoderAttr);
if (attrId < 0) {
return;
}
console.log(`Adding ${attr} attribute`);
const attribute = decoder.GetAttribute(mesh, attrId);
const attributeData = new this.decoderModule.DracoFloat32Array();
decoder.GetAttributeFloatForAllPoints(mesh, attribute, attributeData);
assert(numValues === attributeData.size(), 'Wrong attribute size.');
const attributeDataArray = new Float32Array(numValues);
for (let i = 0; i < numValues; ++i) {
attributeDataArray[i] = attributeData.GetValue(i);
}
this.decoderModule.destroy(attributeData);
meshBuilder.AddFloatAttributeToMesh(newMesh, encoderAttr, numPoints,
stride, attributeDataArray);
});
}
}
/*
encodeMesh(mesh, decoder) {
const encoder = new this.encoderModule.Encoder();
const meshBuilder = new this.encoderModule.MeshBuilder();
// Create a mesh object for storing mesh data.
const newMesh = new this.encoderModule.Mesh();
const numFaces = mesh.num_faces();
const numIndices = numFaces * 3;
const numPoints = mesh.num_points();
const indices = new Uint32Array(numIndices);
console.log("Number of faces " + numFaces);
console.log("Number of vertices " + numPoints);
// Add Faces to mesh
const ia = new this.decoderModule.DracoInt32Array();
for (let i = 0; i < numFaces; ++i) {
decoder.GetFaceFromMesh(mesh, i, ia);
const index = i * 3;
indices[index] = ia.GetValue(0);
indices[index + 1] = ia.GetValue(1);
indices[index + 2] = ia.GetValue(2);
}
this.decoderModule.destroy(ia);
meshBuilder.AddFacesToMesh(newMesh, numFaces, indices);
const attrs = {POSITION: 3, NORMAL: 3, COLOR: 3, TEX_COORD: 2};
Object.keys(attrs).forEach((attr) => {
const stride = attrs[attr];
const numValues = numPoints * stride;
const decoderAttr = this.decoderModule[attr];
const encoderAttr = this.encoderModule[attr];
const attrId = decoder.GetAttributeId(mesh, decoderAttr);
if (attrId < 0) {
return;
}
console.log("Adding %s attribute", attr);
const attribute = decoder.GetAttribute(mesh, attrId);
const attributeData = new this.decoderModule.DracoFloat32Array();
decoder.GetAttributeFloatForAllPoints(mesh, attribute, attributeData);
assert(numValues === attributeData.size(), 'Wrong attribute size.');
const attributeDataArray = new Float32Array(numValues);
for (let i = 0; i < numValues; ++i) {
attributeDataArray[i] = attributeData.GetValue(i);
}
this.decoderModule.destroy(attributeData);
meshBuilder.AddFloatAttributeToMesh(newMesh, encoderAttr, numPoints,
stride, attributeDataArray);
});
let encodedData = new this.encoderModule.DracoInt8Array();
// Set encoding options.
encoder.SetSpeedOptions(5, 5);
encoder.SetAttributeQuantization(this.encoderModule.POSITION, 10);
encoder.SetEncodingMethod(this.encoderModule.MESH_EDGEBREAKER_ENCODING);
// Encoding.
console.log("Encoding...");
const encodedLen = encoder.EncodeMeshToDracoBuffer(newMesh,
encodedData);
this.encoderModule.destroy(newMesh);
if (encodedLen > 0) {
console.log("Encoded size is " + encodedLen);
} else {
console.log("Error: Encoding failed.");
}
// Copy encoded data to buffer.
const outputBuffer = new ArrayBuffer(encodedLen);
const outputData = new Int8Array(outputBuffer);
for (let i = 0; i < encodedLen; ++i) {
outputData[i] = encodedData.GetValue(i);
}
this.encoderModule.destroy(encodedData);
this.encoderModule.destroy(encoder);
this.encoderModule.destroy(meshBuilder);
return outputData;
}
*/