function parseGeometry( geometryNode, relationships, deformerMap ) {

					switch ( geometryNode.attrType ) {

						case 'Mesh':
							return parseMeshGeometry( geometryNode, relationships, deformerMap );
							break;

						case 'NurbsCurve':
							return parseNurbsGeometry( geometryNode, relationships, deformerMap );
							break;

					}

					/**
					 * Specialty function for parsing Mesh based Geometry Nodes.
					 * @param {FBXGeometryNode} geometryNode
					 * @param {{parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}} relationships - Object representing relationships between specific geometry node and other nodes.
					 * @param {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[]}>} deformerMap - Map object of deformers and subDeformers by ID.
					 * @returns {THREE.BufferGeometry}
					 */
					function parseMeshGeometry( geometryNode, relationships, deformerMap ) {

						var FBX_ID = geometryNode.id;
						var name = geometryNode.attrName;
						for ( var i = 0; i < relationships.children.length; ++ i ) {

							if ( deformerMap.has( relationships.children[ i ].ID ) ) {

								var deformer = deformerMap.get( relationships.children[ i ].ID );
								break;

							}

						}

						var geometry = genGeometry( geometryNode, deformer );

						return geometry;

						/**
						 * @param {{map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[]}} deformer - Skeleton representation for geometry instance.
						 * @returns {THREE.BufferGeometry}
						 */
						function genGeometry( geometryNode, deformer ) {

							var geometry = new Geometry();

							//First, each index is going to be its own vertex.
							var vertexBuffer = parseFloatArray( geometryNode.subNodes.Vertices.properties.a );
							var indexBuffer = parseIntArray( geometryNode.subNodes.PolygonVertexIndex.properties.a );

							if ( 'LayerElementNormal' in geometryNode.subNodes ) {

								var normalInfo = getNormals( geometryNode );

							}

							if ( 'LayerElementUV' in geometryNode.subNodes ) {

								var uvInfo = getUVs( geometryNode );

							}

							if ( 'LayerElementMaterial' in geometryNode.subNodes ) {

								var materialInfo = getMaterials( geometryNode );

							}

							var faceVertexBuffer = [];
							var polygonIndex = 0;
							for ( var polygonVertexIndex = 0; polygonVertexIndex < indexBuffer.length; ++ polygonVertexIndex ) {

								var endOfFace;
								var vertexIndex = indexBuffer[ polygonVertexIndex ];
								if ( indexBuffer[ polygonVertexIndex ] < 0 ) {

									vertexIndex = vertexIndex ^ - 1;
									indexBuffer[ polygonVertexIndex ] = vertexIndex;
									endOfFace = true;

								}
								var vertex = new Vertex();
								var weightIndices = [];
								var weights = [];
								vertex.position.fromArray( vertexBuffer, vertexIndex * 3 );

								// If we have a deformer for this geometry, get the skinIndex and skinWeights for this object.
								// They are stored as vertex indices on each deformer, and we need them as deformer indices
								// for each vertex.
								if ( deformer ) {

									for ( var j = 0; j < deformer.array.length; ++ j ) {

										var index = deformer.array[ j ].indices.findIndex( function ( index ) {

											return index === indexBuffer[ polygonVertexIndex ];

										} );

										if ( index !== - 1 ) {

											weights.push( deformer.array[ j ].weights[ index ] );
											weightIndices.push( j );

										}

									}

									if ( weights.length > 4 ) {

										console.warn( 'FBXLoader: Vertex has more than 4 skinning weights assigned to vertex.  Deleting additional weights.' );

										var WIndex = [ 0, 0, 0, 0 ];
										var Weight = [ 0, 0, 0, 0 ];

										for ( var polygonVertexIndex = 0; polygonVertexIndex < weights.length; ++ polygonVertexIndex ) {

											var currentWeight = weights[ polygonVertexIndex ];
											var currentIndex = weightIndices[ polygonVertexIndex ];
											for ( var j = 0; j < Weight.length; ++ j ) {

												if ( currentWeight > Weight[ j ] ) {

													var tmp = Weight[ j ];
													Weight[ j ] = currentWeight;
													currentWeight = tmp;

													tmp = WIndex[ j ];
													WIndex[ j ] = currentIndex;
													currentIndex = tmp;

												}

											}

										}

										weightIndices = WIndex;
										weights = Weight;

									}

									for ( var i = weights.length; i < 4; i ++ ) {

										weights[ i ] = 0;
										weightIndices[ i ] = 0;

									}

									vertex.skinWeights.fromArray( weights );
									vertex.skinIndices.fromArray( weightIndices );

									//vertex.skinWeights.normalize();

								}

								if ( normalInfo ) {

									vertex.normal.fromArray( getData( polygonVertexIndex, polygonIndex, vertexIndex, normalInfo ) );

								}

								if ( uvInfo ) {

									vertex.uv.fromArray( getData( polygonVertexIndex, polygonIndex, vertexIndex, uvInfo ) );

								}



								//Add vertex to face buffer.
								faceVertexBuffer.push( vertex );

								// If index was negative to start with, we have finished this individual face
								// and can generate the face data to the geometry.
								if ( endOfFace ) {

									var face = new Face();
									var materials = getData( polygonVertexIndex, polygonIndex, vertexIndex, materialInfo );
									face.genTrianglesFromVertices( faceVertexBuffer );
									face.materialIndex = materials[ 0 ];
									geometry.faces.push( face );
									faceVertexBuffer = [];
									polygonIndex ++;
									endOfFace = false;

								}

							}

							/**
							 * @type {{vertexBuffer: number[], normalBuffer: number[], uvBuffer: number[], skinIndexBuffer: number[], skinWeightBuffer: number[], materialIndexBuffer: number[]}}
							 */
							var bufferInfo = geometry.flattenToBuffers();

							var geo = new THREE.BufferGeometry();
							geo.name = geometryNode.name;
							geo.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( bufferInfo.vertexBuffer ), 3 ) );

							if ( bufferInfo.normalBuffer.length > 0 ) {

								geo.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( bufferInfo.normalBuffer ), 3 ) );

							}
							if ( bufferInfo.uvBuffer.length > 0 ) {

								geo.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( bufferInfo.uvBuffer ), 2 ) );

							}

							if ( deformer ) {

								geo.addAttribute( 'skinIndex', new THREE.BufferAttribute( new Float32Array( bufferInfo.skinIndexBuffer ), 4 ) );

								geo.addAttribute( 'skinWeight', new THREE.BufferAttribute( new Float32Array( bufferInfo.skinWeightBuffer ), 4 ) );

								geo.FBX_Deformer = deformer;

							}

							// Convert the material indices of each vertex into rendering groups on the geometry.
							var prevMaterialIndex = bufferInfo.materialIndexBuffer[ 0 ];
							var startIndex = 0;
							for ( var materialBufferIndex = 0; materialBufferIndex < bufferInfo.materialIndexBuffer.length; ++ materialBufferIndex ) {

								if ( bufferInfo.materialIndexBuffer[ materialBufferIndex ] !== prevMaterialIndex ) {

									geo.addGroup( startIndex, materialBufferIndex - startIndex, prevMaterialIndex );
									startIndex = materialBufferIndex;
									prevMaterialIndex = bufferInfo.materialIndexBuffer[ materialBufferIndex ];

								}

							}

							return geo;

							/**
							 * Parses normal information for geometry.
							 * @param {FBXGeometryNode} geometryNode
							 * @returns {{dataSize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}}
							 */
							function getNormals( geometryNode ) {

								var NormalNode = geometryNode.subNodes.LayerElementNormal[ 0 ];

								var mappingType = NormalNode.properties.MappingInformationType;
								var referenceType = NormalNode.properties.ReferenceInformationType;
								var buffer = parseFloatArray( NormalNode.subNodes.Normals.properties.a );
								var indexBuffer = [];
								if ( referenceType === 'IndexToDirect' ) {

									indexBuffer = parseIntArray( NormalNode.subNodes.NormalIndex.properties.a );

								}

								return {
									dataSize: 3,
									buffer: buffer,
									indices: indexBuffer,
									mappingType: mappingType,
									referenceType: referenceType
								};

							}

							/**
							 * Parses UV information for geometry.
							 * @param {FBXGeometryNode} geometryNode
							 * @returns {{dataSize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}}
							 */
							function getUVs( geometryNode ) {

								var UVNode = geometryNode.subNodes.LayerElementUV[ 0 ];

								var mappingType = UVNode.properties.MappingInformationType;
								var referenceType = UVNode.properties.ReferenceInformationType;
								var buffer = parseFloatArray( UVNode.subNodes.UV.properties.a );
								var indexBuffer = [];
								if ( referenceType === 'IndexToDirect' ) {

									indexBuffer = parseIntArray( UVNode.subNodes.UVIndex.properties.a );

								}

								return {
									dataSize: 2,
									buffer: buffer,
									indices: indexBuffer,
									mappingType: mappingType,
									referenceType: referenceType
								};

							}

							/**
							 * Parses material application information for geometry.
							 * @param {FBXGeometryNode}
							 * @returns {{dataSize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}}
							 */
							function getMaterials( geometryNode ) {

								var MaterialNode = geometryNode.subNodes.LayerElementMaterial[ 0 ];
								var mappingType = MaterialNode.properties.MappingInformationType;
								var referenceType = MaterialNode.properties.ReferenceInformationType;
								var materialIndexBuffer = parseIntArray( MaterialNode.subNodes.Materials.properties.a );

								// Since materials are stored as indices, there's a bit of a mismatch between FBX and what
								// we expect.  So we create an intermediate buffer that points to the index in the buffer,
								// for conforming with the other functions we've written for other data.
								var materialIndices = [];
								materialIndexBuffer.forEach( function ( materialIndex, index ) {

									materialIndices.push( index );

								} );

								return {
									dataSize: 1,
									buffer: materialIndexBuffer,
									indices: materialIndices,
									mappingType: mappingType,
									referenceType: referenceType
								};

							}

							/**
							 * Function uses the infoObject and given indices to return value array of object.
							 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
							 * @param {number} polygonIndex - Index of polygon in geometry.
							 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
							 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
							 * @returns {number[]}
							 */
							function getData( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

								var GetData = {

									ByPolygonVertex: {

										/**
										 * Function uses the infoObject and given indices to return value array of object.
										 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
										 * @param {number} polygonIndex - Index of polygon in geometry.
										 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
										 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
										 * @returns {number[]}
										 */
										Direct: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

											return infoObject.buffer.slice( ( polygonVertexIndex * infoObject.dataSize ), ( polygonVertexIndex * infoObject.dataSize ) + infoObject.dataSize );

										},

										/**
										 * Function uses the infoObject and given indices to return value array of object.
										 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
										 * @param {number} polygonIndex - Index of polygon in geometry.
										 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
										 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
										 * @returns {number[]}
										 */
										IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

											var index = infoObject.indices[ polygonVertexIndex ];
											return infoObject.buffer.slice( ( index * infoObject.dataSize ), ( index * infoObject.dataSize ) + infoObject.dataSize );

										}

									},

									ByPolygon: {

										/**
										 * Function uses the infoObject and given indices to return value array of object.
										 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
										 * @param {number} polygonIndex - Index of polygon in geometry.
										 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
										 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
										 * @returns {number[]}
										 */
										Direct: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

											return infoObject.buffer.slice( polygonIndex * infoObject.dataSize, polygonIndex * infoObject.dataSize + infoObject.dataSize );

										},

										/**
										 * Function uses the infoObject and given indices to return value array of object.
										 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
										 * @param {number} polygonIndex - Index of polygon in geometry.
										 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
										 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
										 * @returns {number[]}
										 */
										IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

											var index = infoObject.indices[ polygonIndex ];
											return infoObject.buffer.slice( index * infoObject.dataSize, index * infoObject.dataSize + infoObject.dataSize );

										}

									},

									AllSame: {

										/**
										 * Function uses the infoObject and given indices to return value array of object.
										 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
										 * @param {number} polygonIndex - Index of polygon in geometry.
										 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
										 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
										 * @returns {number[]}
										 */
										IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

											return infoObject.buffer.slice( infoObject.indices[ 0 ] * infoObject.dataSize, infoObject.indices[ 0 ] * infoObject.dataSize + infoObject.dataSize );

										}

									}

								};

								return GetData[ infoObject.mappingType ][ infoObject.referenceType ]( polygonVertexIndex, polygonIndex, vertexIndex, infoObject );

							}

						}

					}

					/**
					 * Specialty function for parsing NurbsCurve based Geometry Nodes.
					 * @param {FBXGeometryNode} geometryNode
					 * @param {{parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}} relationships
					 * @returns {THREE.BufferGeometry}
					 */
					function parseNurbsGeometry( geometryNode, relationships ) {

						if ( THREE.NURBSCurve === undefined ) {

							console.error( "THREE.FBXLoader relies on THREE.NURBSCurve for any nurbs present in the model.  Nurbs will show up as empty geometry." );
							return new THREE.BufferGeometry();

						}

						var order = parseInt( geometryNode.properties.Order );

						if ( isNaN( order ) ) {

							console.error( "FBXLoader: Invalid Order " + geometryNode.properties.Order + " given for geometry ID: " + geometryNode.id );
							return new THREE.BufferGeometry();

						}

						var knots = parseFloatArray( geometryNode.subNodes.KnotVector.properties.a );
						var controlPoints = [];
						var pointsValues = parseFloatArray( geometryNode.subNodes.Points.properties.a );

						for ( var i = 0; i < pointsValues.length; i += 4 ) {

							controlPoints.push( new THREE.Vector4( pointsValues[ i ], pointsValues[ i + 1 ], pointsValues[ i + 2 ], pointsValues[ i + 3 ] ) );

						}

						if ( geometryNode.properties.Form === 'Closed' ) {

							controlPoints.push( controlPoints[ 0 ] );

						}

						var curve = new THREE.NURBSCurve( order - 1, knots, controlPoints );
						var vertices = curve.getPoints( controlPoints.length * 1.5 );

						var vertexBuffer = [];
						vertices.forEach( function ( position ) {

							var array = position.toArray();
							vertexBuffer = vertexBuffer.concat( array );

						} );

						var geometry = new THREE.BufferGeometry();
						geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertexBuffer ), 3 ) );

						return geometry;

					}

				}
Generates BufferGeometry from FBXGeometryNode.
@param {FBXGeometryNode} geometryNode
@param {{parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}} relationships
@param {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[]}>} deformerMap
@returns {THREE.BufferGeometry}