mirror of
https://git.mirrors.martin98.com/https://github.com/google/draco
synced 2025-04-21 13:19:57 +08:00

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
198 lines
7.3 KiB
JavaScript
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!");
|
|
}
|
|
});
|
|
}
|
|
|