draco/javascript/npm/draco3d/draco_nodejs_example.js
Ondrej Stava 81d73904ac Draco updated to 1.0.0 version
The latest version of Draco brings many new enhancements to improve the
development experience:
* Stable API release
* Support for npm Javascript package management
* Javascript based encoder
* Generalized metadata for meshes and point clouds
  * Now supporting material properties included along with encoded file
* Improved compression rates:
  * 15% better compression on smaller models
  * 40% better compression of normals
* Performance improvements (~10% faster encoding, decoding)
* Reduced GPU memory usage:
  * Option to store decoded quantized attributes
  * Support for triangle strip connectivity on decoded meshes
* iOS 9 Javascript decoder
* Bitstream specification now available
2017-07-28 14:25:10 -07:00

198 lines
7.3 KiB
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.
//
'use_strict';
const fs = require('fs');
const draco3d = require('./draco3d');
const decoderModule = draco3d.createDecoderModule({});
const encoderModule = draco3d.createEncoderModule({});
fs.readFile('./bunny.drc', function(err, data) {
if (err) {
return console.log(err);
}
console.log("Decoding file of size " + data.byteLength + " ..");
// Decode mesh
const decoder = new decoderModule.Decoder();
let decodedGeometry = decodeDracoData(data, decoder);
// Encode mesh
encodeMeshToFile(decodedGeometry, decoder);
decoderModule.destroy(decoder);
decoderModule.destroy(decodedGeometry);
});
function decodeDracoData(rawBuffer, decoder) {
const buffer = new decoderModule.DecoderBuffer();
buffer.Init(new Int8Array(rawBuffer), rawBuffer.byteLength);
const geometryType = decoder.GetEncodedGeometryType(buffer);
let dracoGeometry;
let status;
if (geometryType === decoderModule.TRIANGULAR_MESH) {
dracoGeometry = new decoderModule.Mesh();
status = decoder.DecodeBufferToMesh(buffer, dracoGeometry);
} else if (geometryType === decoderModule.POINT_CLOUD) {
dracoGeometry = new decoderModule.PointCloud();
status = decoder.DecodeBufferToPointCloud(buffer, dracoGeometry);
} else {
const errorMsg = 'Error: Unknown geometry type.';
console.error(errorMsg);
}
decoderModule.destroy(buffer);
return dracoGeometry;
}
function encodeMeshToFile(mesh, decoder) {
const encoder = new encoderModule.Encoder();
const meshBuilder = new encoderModule.MeshBuilder();
// Create a mesh object for storing mesh data.
const newMesh = new encoderModule.Mesh();
const numFaces = mesh.num_faces();
const numIndices = numFaces * 3;
const numPoints = mesh.num_points();
const numVertexCoord = numPoints * 3;
console.log("Number of faces " + numFaces);
console.log("Number of vertices " + numPoints);
let indices = new Uint32Array(numIndices);
// Add Faces to mesh
const ia = new 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);
}
decoderModule.destroy(ia);
meshBuilder.AddFacesToMesh(newMesh, numFaces, indices);
// Add position data to mesh.
const posAttId = decoder.GetAttributeId(mesh, decoderModule.POSITION);
if (posAttId === -1) {
console.log("No position attribute found.");
encoderModule.destroy(newMesh);
encoderModule.destroy(encoder);
return;
}
const posAttribute = decoder.GetAttribute(mesh, posAttId);
const posAttributeData = new decoderModule.DracoFloat32Array();
decoder.GetAttributeFloatForAllPoints(
mesh, posAttribute, posAttributeData);
let vertices = new Float32Array(numVertexCoord);
for (let i = 0; i < numVertexCoord; i += 3) {
vertices[i] = posAttributeData.GetValue(i);
vertices[i + 1] = posAttributeData.GetValue(i + 1);
vertices[i + 2] = posAttributeData.GetValue(i + 2);
}
decoderModule.destroy(posAttributeData);
meshBuilder.AddFloatAttributeToMesh(newMesh, encoderModule.POSITION,
numPoints, 3, vertices);
const normalAttId = decoder.GetAttributeId(mesh, decoderModule.NORMAL);
if (normalAttId > -1) {
console.log("Adding normal attribute.");
const norAttribute = decoder.GetAttribute(mesh, normalAttId);
const norAttributeData = new decoderModule.DracoFloat32Array();
decoder.GetAttributeFloatForAllPoints(mesh, norAttribute,
norAttributeData);
const normals = new Float32Array(numVertexCoord);
for (let i = 0; i < numVertexCoord; i += 3) {
normals[i] = norAttributeData.GetValue(i);
normals[i + 1] = norAttributeData.GetValue(i + 1);
normals[i + 2] = norAttributeData.GetValue(i + 2);
}
decoderModule.destroy(norAttributeData);
meshBuilder.AddFloatAttributeToMesh(newMesh, encoderModule.NORMAL,
numPoints, 3, normals);
}
const texAttId = decoder.GetAttributeId(mesh, decoderModule.TEX_COORD);
if (texAttId > -1) {
const texAttribute = decoder.GetAttribute(mesh, texAttId);
const texAttributeData = new decoderModule.DracoFloat32Array();
decoder.GetAttributeFloatForAllPoints(mesh, texAttribute,
texAttributeData);
assertEquals(numVertexCoord, texAttributeData.size());
const texcoords = new Float32Array(numVertexCoord);
for (let i = 0; i < numVertexCoord; i += 3) {
texcoords[i] = texAttributeData.GetValue(i);
texcoords[i + 1] = texAttributeData.GetValue(i + 1);
texcoords[i + 2] = texAttributeData.GetValue(i + 2);
}
decoderModule.destroy(texAttributeData);
meshBuilder.AddFloatAttributeToMesh(newMesh, encoderModule.TEX_COORD,
numPoints, 3, normals);
}
const colorAttId = decoder.GetAttributeId(mesh, decoderModule.COLOR);
if (colorAttId > -1) {
const colAttribute = decoder.GetAttribute(mesh, colorAttId);
const colAttributeData = new decoderModule.DracoFloat32Array();
decoder.GetAttributeFloatForAllPoints(mesh, colAttribute,
colAttributeData);
assertEquals(numVertexCoord, colAttributeData.size());
const colors = new Float32Array(numVertexCoord);
for (let i = 0; i < numVertexCoord; i += 3) {
colors[i] = colAttributeData.GetValue(i);
colors[i + 1] = colAttributeData.GetValue(i + 1);
colors[i + 2] = colAttributeData.GetValue(i + 2);
}
decoderModule.destroy(colAttributeData);
meshBuilder.AddFloatAttributeToMesh(newMesh, encoderModule.COLOR,
numPoints, 3, normals);
}
let encodedData = new encoderModule.DracoInt8Array();
// Set encoding options.
encoder.SetSpeedOptions(5, 5);
encoder.SetAttributeQuantization(encoderModule.POSITION, 10);
encoder.SetEncodingMethod(encoderModule.MESH_EDGEBREAKER_ENCODING);
// Encoding.
console.log("Encoding...");
const encodedLen = encoder.EncodeMeshToDracoBuffer(newMesh,
encodedData);
encoderModule.destroy(newMesh);
if (encodedLen > 0) {
console.log("Encoded size is " + encodedLen);
} else {
console.log("Error: Encoding failed.");
}
// Copy encoded data to buffer.
let outputBuffer = new ArrayBuffer(encodedLen);
let outputData = new Int8Array(outputBuffer);
for (let i = 0; i < encodedLen; ++i) {
outputData[i] = encodedData.GetValue(i);
}
encoderModule.destroy(encodedData);
encoderModule.destroy(encoder);
encoderModule.destroy(meshBuilder);
// Write to file. You can view the the file using webgl_loader_draco.html
// example.
fs.writeFile("bunny_10.drc", Buffer(outputBuffer), "binary", function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});
}