DRACOLoader.js 11.0 KB
Newer Older
E
edsilv 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright 2016 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.
//
15 16
'use strict';

E
edsilv 已提交
17 18 19 20
THREE.DRACOLoader = function(manager) {
    this.manager = (manager !== undefined) ? manager :
        THREE.DefaultLoadingManager;
    this.materials = null;
21
    this.verbosity = 0;
E
edsilv 已提交
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
};


THREE.DRACOLoader.prototype = {

    constructor: THREE.DRACOLoader,

    load: function(url, onLoad, onProgress, onError) {
        const scope = this;
        const loader = new THREE.FileLoader(scope.manager);
        loader.setPath(this.path);
        loader.setResponseType('arraybuffer');
        loader.load(url, function(blob) {
            onLoad(scope.decodeDracoFile(blob));
        }, onProgress, onError);
    },

    setPath: function(value) {
        this.path = value;
    },

43 44 45 46
    setVerbosity: function(level) {
        this.verbosity = level;
    },

47 48
    decodeDracoFile: ( function() {
        let dracoDecoder;
E
edsilv 已提交
49

50 51
        if (typeof DracoModule === 'function') {
          dracoDecoder = DracoModule();
E
edsilv 已提交
52
        } else {
53 54
          console.error('THREE.DRACOLoader: DracoModule not found.');
          return;
E
edsilv 已提交
55 56
        }

57 58 59 60 61 62 63 64 65 66 67 68 69 70
        return function(rawBuffer) {
          const scope = this;
          /*
           * Here is how to use Draco Javascript decoder and get the geometry.
           */
          const buffer = new dracoDecoder.DecoderBuffer();
          buffer.Init(new Int8Array(rawBuffer), rawBuffer.byteLength);
          const wrapper = new dracoDecoder.WebIDLWrapper();

          /*
           * Determine what type is this file: mesh or point cloud.
           */
          const geometryType = wrapper.GetEncodedGeometryType(buffer);
          if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
71 72 73
            if (this.verbosity > 0) {
              console.log('Loaded a mesh.');
            }
74
          } else if (geometryType == dracoDecoder.POINT_CLOUD) {
75 76 77
            if (this.verbosity > 0) {
              console.log('Loaded a point cloud.');
            }
78
          } else {
79 80
            const errorMsg = 'THREE.DRACOLoader: Unknown geometry type.'
            console.error(errorMsg);
81 82 83 84 85 86 87 88 89
            throw new Error(errorMsg);
          }
          return scope.convertDracoGeometryTo3JS(wrapper, geometryType, buffer,
                                                 dracoDecoder);
        }
    } )(),

    convertDracoGeometryTo3JS: function(wrapper, geometryType, buffer,
                                        dracoDecoder) {
E
edsilv 已提交
90
        let dracoGeometry;
91 92
        const start_time = performance.now();
        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
E
edsilv 已提交
93 94 95 96
          dracoGeometry = wrapper.DecodeMeshFromBuffer(buffer);
        } else {
          dracoGeometry = wrapper.DecodePointCloudFromBuffer(buffer);
        }
97 98
        const decode_end = performance.now();
        dracoDecoder.destroy(buffer);
E
edsilv 已提交
99 100 101
        /*
         * Example on how to retrieve mesh and attributes.
         */
102 103
        let numFaces, numPoints;
        let numVertexCoordinates, numTextureCoordinates, numAttributes;
E
edsilv 已提交
104 105
        // For output basic geometry information.
        let geometryInfoStr;
106
        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
E
edsilv 已提交
107
          numFaces = dracoGeometry.num_faces();
108 109 110
          if (this.verbosity > 0) {
            console.log('Number of faces loaded: ' + numFaces.toString());
          }
E
edsilv 已提交
111 112 113 114 115
        } else {
          numFaces = 0;
        }
        numPoints = dracoGeometry.num_points();
        numVertexCoordinates = numPoints * 3;
116
        numTextureCoordinates = numPoints * 2;
E
edsilv 已提交
117
        numAttributes = dracoGeometry.num_attributes();
118 119 120 121 122
        if (this.verbosity > 0) {
          console.log('Number of points loaded: ' + numPoints.toString());
          console.log('Number of attributes loaded: ' +
              numAttributes.toString());
        }
E
edsilv 已提交
123 124 125

        // Get position attribute. Must exists.
        const posAttId = wrapper.GetAttributeId(dracoGeometry,
126
                                                dracoDecoder.POSITION);
E
edsilv 已提交
127
        if (posAttId == -1) {
128 129
          const errorMsg = 'THREE.DRACOLoader: No position attribute found.';
          console.error(errorMsg);
130 131
          dracoDecoder.destroy(wrapper);
          dracoDecoder.destroy(dracoGeometry);
E
edsilv 已提交
132 133 134
          throw new Error(errorMsg);
        }
        const posAttribute = wrapper.GetAttribute(dracoGeometry, posAttId);
135
        const posAttributeData = new dracoDecoder.DracoFloat32Array();
E
edsilv 已提交
136 137 138
        wrapper.GetAttributeFloatForAllPoints(
            dracoGeometry, posAttribute, posAttributeData);
        // Get color attributes if exists.
139 140
        const colorAttId = wrapper.GetAttributeId(dracoGeometry,
                                                  dracoDecoder.COLOR);
E
edsilv 已提交
141 142
        let colAttributeData;
        if (colorAttId != -1) {
143 144 145
          if (this.verbosity > 0) {
            console.log('Loaded color attribute.');
          }
E
edsilv 已提交
146
          const colAttribute = wrapper.GetAttribute(dracoGeometry, colorAttId);
147
          colAttributeData = new dracoDecoder.DracoFloat32Array();
E
edsilv 已提交
148 149 150 151 152 153
          wrapper.GetAttributeFloatForAllPoints(dracoGeometry, colAttribute,
                                                colAttributeData);
        }

        // Get normal attributes if exists.
        const normalAttId =
154
            wrapper.GetAttributeId(dracoGeometry, dracoDecoder.NORMAL);
E
edsilv 已提交
155 156
        let norAttributeData;
        if (normalAttId != -1) {
157 158 159
          if (this.verbosity > 0) {
            console.log('Loaded normal attribute.');
          }
E
edsilv 已提交
160
          const norAttribute = wrapper.GetAttribute(dracoGeometry, normalAttId);
161
          norAttributeData = new dracoDecoder.DracoFloat32Array();
E
edsilv 已提交
162 163 164 165
          wrapper.GetAttributeFloatForAllPoints(dracoGeometry, norAttribute,
                                                norAttributeData);
        }

166 167 168 169 170
        // Get texture coord attributes if exists.
        const texCoordAttId =
            wrapper.GetAttributeId(dracoGeometry, dracoDecoder.TEX_COORD);
        let textCoordAttributeData;
        if (texCoordAttId != -1) {
171 172 173
          if (this.verbosity > 0) {
            console.log('Loaded texture coordinate attribute.');
          }
174 175 176 177 178 179 180 181
          const texCoordAttribute = wrapper.GetAttribute(dracoGeometry,
                                                         texCoordAttId);
          textCoordAttributeData = new dracoDecoder.DracoFloat32Array();
          wrapper.GetAttributeFloatForAllPoints(dracoGeometry,
                                                texCoordAttribute,
                                                textCoordAttributeData);
        }

E
edsilv 已提交
182
        // Structure for converting to THREEJS geometry later.
183
        const numIndices = numFaces * 3;
E
edsilv 已提交
184
        const geometryBuffer = {
185 186 187 188 189
            indices: new Uint32Array(numIndices),
            vertices: new Float32Array(numVertexCoordinates),
            normals: new Float32Array(numVertexCoordinates),
            uvs: new Float32Array(numTextureCoordinates),
            colors: new Float32Array(numVertexCoordinates)
E
edsilv 已提交
190
        };
191

E
edsilv 已提交
192
        for (let i = 0; i < numVertexCoordinates; i += 3) {
193 194 195
            geometryBuffer.vertices[i] = posAttributeData.GetValue(i);
            geometryBuffer.vertices[i + 1] = posAttributeData.GetValue(i + 1);
            geometryBuffer.vertices[i + 2] = posAttributeData.GetValue(i + 2);
E
edsilv 已提交
196
            // Add color.
197
            // ThreeJS vertex colors need to be normalized to properly display
E
edsilv 已提交
198
            if (colorAttId != -1) {
199
              geometryBuffer.colors[i] = colAttributeData.GetValue(i) / 255;
200 201 202 203
              geometryBuffer.colors[i + 1] =
                  colAttributeData.GetValue(i + 1) / 255;
              geometryBuffer.colors[i + 2] =
                  colAttributeData.GetValue(i + 2) / 255;
E
edsilv 已提交
204
            } else {
205 206 207 208
              // Default is white. This is faster than TypedArray.fill().
              geometryBuffer.colors[i] = 1.0;
              geometryBuffer.colors[i + 1] = 1.0;
              geometryBuffer.colors[i + 2] = 1.0;
E
edsilv 已提交
209 210 211
            }
            // Add normal.
            if (normalAttId != -1) {
212 213 214
              geometryBuffer.normals[i] = norAttributeData.GetValue(i);
              geometryBuffer.normals[i + 1] = norAttributeData.GetValue(i + 1);
              geometryBuffer.normals[i + 2] = norAttributeData.GetValue(i + 2);
E
edsilv 已提交
215 216
            }
        }
217 218 219 220 221 222 223 224 225 226

        // Add texture coordinates.
        if (texCoordAttId != -1) {
          for (let i = 0; i < numTextureCoordinates; i += 2) {
            geometryBuffer.uvs[i] = textCoordAttributeData.GetValue(i);
            geometryBuffer.uvs[i + 1] = textCoordAttributeData.GetValue(i + 1);
          }
        }

        dracoDecoder.destroy(posAttributeData);
E
edsilv 已提交
227
        if (colorAttId != -1)
228
          dracoDecoder.destroy(colAttributeData);
E
edsilv 已提交
229
        if (normalAttId != -1)
230 231 232
          dracoDecoder.destroy(norAttributeData);
        if (texCoordAttId != -1)
          dracoDecoder.destroy(textCoordAttributeData);
E
edsilv 已提交
233 234

        // For mesh, we need to generate the faces.
235 236
        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
          const ia = new dracoDecoder.DracoInt32Array();
E
edsilv 已提交
237 238
          for (let i = 0; i < numFaces; ++i) {
            wrapper.GetFaceFromMesh(dracoGeometry, i, ia);
239 240 241 242
            const index = i * 3;
            geometryBuffer.indices[index] = ia.GetValue(0);
            geometryBuffer.indices[index + 1] = ia.GetValue(1);
            geometryBuffer.indices[index + 2] = ia.GetValue(2);
E
edsilv 已提交
243
          }
244
          dracoDecoder.destroy(ia);
E
edsilv 已提交
245
        }
246 247
        dracoDecoder.destroy(wrapper);
        dracoDecoder.destroy(dracoGeometry);
E
edsilv 已提交
248 249 250

        // Import data to Three JS geometry.
        const geometry = new THREE.BufferGeometry();
251
        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
E
edsilv 已提交
252 253 254 255 256 257 258 259 260 261 262 263
          geometry.setIndex(new(geometryBuffer.indices.length > 65535 ?
                THREE.Uint32BufferAttribute : THREE.Uint16BufferAttribute)
              (geometryBuffer.indices, 1));
        }
        geometry.addAttribute('position',
            new THREE.Float32BufferAttribute(geometryBuffer.vertices, 3));
        geometry.addAttribute('color',
            new THREE.Float32BufferAttribute(geometryBuffer.colors, 3));
        if (normalAttId != -1) {
          geometry.addAttribute('normal',
              new THREE.Float32BufferAttribute(geometryBuffer.normals, 3));
        }
264 265 266 267
        if (texCoordAttId != -1) {
          geometry.addAttribute('uv',
              new THREE.Float32BufferAttribute(geometryBuffer.uvs, 2));
        }
268 269 270 271 272 273 274
        this.decode_time = decode_end - start_time;
        this.import_time = performance.now() - decode_end;

        if (this.verbosity > 0) {
          console.log('Decode time: ' + this.decode_time);
          console.log('Import time: ' + this.import_time);
        }
E
edsilv 已提交
275 276 277
        return geometry;
    }
};