瀏覽代碼

Merge branch 'dev' of https://github.com/bartmcleod/three.js into dev

Mr.doob 11 年之前
父節點
當前提交
6a535af21b
共有 1 個文件被更改,包括 521 次插入173 次删除
  1. 521 173
      examples/js/loaders/VRMLLoader.js

+ 521 - 173
examples/js/loaders/VRMLLoader.js

@@ -8,6 +8,20 @@ THREE.VRMLLoader.prototype = {
 
 
 	constructor: THREE.VRMLLoader,
 	constructor: THREE.VRMLLoader,
 
 
+    // for IndexedFaceSet support
+    isRecordingPoints: false,
+    isRecordingFaces: false,
+    points: [],
+    indexes : [],
+
+    // for Background support
+    isRecordingAngles: false,
+    isRecordingColors: false,
+    angles: [],
+    colors: [],
+
+    recordingFieldname: null,
+
 	load: function ( url, callback ) {
 	load: function ( url, callback ) {
 
 
 		var scope = this;
 		var scope = this;
@@ -47,12 +61,379 @@ THREE.VRMLLoader.prototype = {
 		};
 		};
 
 
 		var parseV2 = function ( lines, scene ) {
 		var parseV2 = function ( lines, scene ) {
+            var defines = {};
+            var float_pattern = /(\b|\-|\+)([\d\.e]+)/;
+            var float3_pattern = /([\d\.\+\-e]+),?\s+([\d\.\+\-e]+),?\s+([\d\.\+\-e]+)/;
+
+
+
+            /**
+            * Interpolates colors a and b following their relative distance
+            * expressed by t.
+            *
+            * @param float a
+            * @param float b
+            * @param float t
+            * @returns {Color}
+            */
+            var interpolateColors = function(a, b, t) {
+               var deltaR = a.r - b.r;
+               var deltaG = a.g - b.g;
+               var deltaB = a.b - b.b;
+
+               var c = new THREE.Color();
+
+               c.r = a.r - t * deltaR;
+               c.g = a.g - t * deltaG;
+               c.b = a.b - t * deltaB;
+
+               return c;
+            };
+
+            /**
+             * Vertically paints the faces interpolating between the
+             * specified colors at the specified angels. This is used for the Background
+             * node, but could be applied to other nodes with multiple faces as well.
+             *
+             * The first angle is never specified, it is the Zenith (0 rad). Angles are specified
+             * in radians. The geometry is thought a sphere, but could be anything.
+             *
+             * You must specify one more color than you have angles at the beginning of the colors array.
+             * This is the color of the Zenith (the top of the shape).
+             *
+             * @param geometry
+             * @param radius
+             * @param angles
+             * @param colors
+             * @param boolean directionIsDown Whether to work bottom up or top down (default)
+             */
+            var paintFaces = function (geometry, radius, angles, colors, directionIsDown) {
+
+                var f, n, p, vertexIndex, color;
+
+                var direction = directionIsDown ? 1 : -1;
+
+                var faceIndices = [ 'a', 'b', 'c', 'd' ];
+
+                var coord = [ ], aColor, bColor, t = 1, A = {}, B = {}, applyColor = false, colorIndex;
+
+                for ( var k = 0; k < angles.length; k++ ) {
+
+                    var vec = { };
+
+                    // push the vector at which the color changes
+                    vec.y = direction * ( Math.cos( angles[k] ) * radius);
+
+                    vec.x = direction * ( Math.sin( angles[k] ) * radius);
+
+                    coord.push( vec );
+
+                }
+
+                // painting the colors on the faces
+                for ( var i = 0; i < geometry.faces.length ; i++ ) {
+
+                    f  = geometry.faces[ i ];
+
+                    n = ( f instanceof THREE.Face3 ) ? 3 : 4;
+
+                    for ( var j = 0; j < n; j++ ) {
+
+                        vertexIndex = f[ faceIndices[ j ] ];
+
+                        p = geometry.vertices[ vertexIndex ];
+
+                        for ( var index = 0; index < colors.length; index++ ) {
+
+                            // linear interpolation between aColor and bColor, calculate proportion
+                            // A is previous point (angle)
+                            if ( index === 0 ) {
+
+                                A.x = 0;
+                                A.y = directionIsDown ? radius : -1 * radius;
+
+                            } else {
+
+                                A.x = coord[ index-1 ].x;
+                                A.y = coord[ index-1 ].y;
+
+                            }
+
+                            // B is current point (angle)
+                            B = coord[index];
+
+                            if ( undefined !== B ) {
+                                // p has to be between the points A and B which we interpolate
+                                applyColor = directionIsDown ? p.y <= A.y && p.y > B.y : p.y >= A.y && p.y < B.y;
+
+                                if (applyColor) {
+
+                                    bColor = colors[ index + 1 ];
+
+                                    aColor = colors[ index ];
+
+                                    // below is simple linear interpolation
+                                    t = Math.abs( p.y - A.y ) / ( A.y - B.y );
+
+                                    // to make it faster, you can only calculate this if the y coord changes, the color is the same for points with the same y
+                                    color = interpolateColors( aColor, bColor, t );
+
+                                    f.vertexColors[ j ] = color;
+                                }
+
+                            } else if ( undefined === f.vertexColors[ j ] ) {
+                                colorIndex = directionIsDown ? colors.length -1 : 0;
+                                f.vertexColors[ j ] = colors[ colorIndex ];
+
+                            }
+                        }
+
+
+                    }
+
+                }
+            };
+
+            var parseProperty = function (node, line) {
+
+                var parts = [], part, property = {}, fieldName;
+
+                /**
+                 * Expression for matching relevant information, such as a name or value, but not the separators
+                 * @type {RegExp}
+                 */
+                var regex = /[^\s,\[\]]+/g;
+
+                var point, index, angles, colors;
+
+                while (null != ( part = regex.exec(line) ) ) {
+                    parts.push(part[0]);
+                }
+
+                fieldName = parts[0];
+
+
+                // trigger several recorders
+                switch (fieldName) {
+                    case 'skyAngle':
+                    case 'groundAngle':
+                        this.recordingFieldname = fieldName;
+                        this.isRecordingAngles = true;
+                        this.angles = [];
+                        break;
+                    case 'skyColor':
+                    case 'groundColor':
+                        this.recordingFieldname = fieldName;
+                        this.isRecordingColors = true;
+                        this.colors = [];
+                        break;
+                    case 'point':
+                        this.recordingFieldname = fieldName;
+                        this.isRecordingPoints = true;
+                        this.points = [];
+                        break;
+                    case 'coordIndex':
+                        this.recordingFieldname = fieldName;
+                        this.isRecordingFaces = true;
+                        this.indexes = [];
+                        break;
+                }
+
+                if (this.isRecordingFaces) {
+
+                    // the parts hold the indexes as strings
+                    if (parts.length > 0) {
+                        index = [];
+
+                        for (var ind = 0;ind < parts.length; ind++) {
+
+                            // the part should either be positive integer or -1
+                            if (!/(-?\d+)/.test( parts[ind]) ) {
+                                continue;
+                            }
+
+                            // end of current face
+                            if (parts[ind] === "-1") {
+                                if (index.length > 0) {
+                                   this.indexes.push(index);
+                                }
+
+                                // start new one
+                                index = [];
+                            } else {
+                                index.push(parseInt( parts[ind]) );
+                            }
+                        }
+
+                    }
+
+                    // end
+                    if (/]/.exec(line)) {
+                        this.isRecordingFaces = false;
+                        node.coordIndex = this.indexes;
+                    }
+
+                } else if (this.isRecordingPoints) {
+
+                    parts = float3_pattern.exec(line);
+
+                    // parts may be empty on first and last line
+                    if (null != parts) {
+                        point = {
+                            x: parseFloat(parts[1]),
+                            y: parseFloat(parts[2]),
+                            z: parseFloat(parts[3])
+                        };
+
+                        this.points.push(point);
+                    }
+
+                    // end
+                    if ( /]/.exec(line) ) {
+                        this.isRecordingPoints = false;
+                        node.points = this.points;
+                    }
+
+                } else if ( this.isRecordingAngles ) {
+
+                    // the parts hold the angles as strings
+                    if ( parts.length > 0 ) {
+
+                        for ( var ind = 0;ind < parts.length; ind++ ) {
+
+                            // the part should be a float
+                            if ( ! float_pattern.test( parts[ind] ) ) {
+                                continue;
+                            }
+
+                            this.angles.push( parseFloat( parts[ind] ) );
+                        }
+
+                    }
+
+                    // end
+                    if ( /]/.exec(line) ) {
+                        this.isRecordingAngles = false;
+                        node[this.recordingFieldname] = this.angles;
+                    }
+
+                } else if (this.isRecordingColors) {
+                    // this is the float3 regex with the g modifier added, you could also explode the line by comma first (faster probably)
+                    var float3_repeatable = /([\d\.\+\-e]+),?\s+([\d\.\+\-e]+),?\s+([\d\.\+\-e]+)/g;
+
+                    while( null !== (parts = float3_repeatable.exec(line) ) ) {
+
+                        color = {
+                            r: parseFloat(parts[1]),
+                            g: parseFloat(parts[2]),
+                            b: parseFloat(parts[3])
+                        };
+
+                        this.colors.push(color);
+
+                    }
+
+                    // end
+                    if (/]/.exec(line)) {
+                        this.isRecordingColors = false;
+                        node[this.recordingFieldname] = this.colors;
+                    }
+
+                } else if ( parts[parts.length -1] !== 'NULL' && fieldName !== 'children') {
+
+                    switch (fieldName) {
+
+                        case 'diffuseColor':
+                        case 'emissiveColor':
+                        case 'specularColor':
+                        case 'color':
+
+                            if (parts.length != 4) {
+                                console.warn('Invalid color format detected for ' + fieldName );
+                                break;
+                            }
+
+                            property = {
+                                'r'         : parseFloat(parts[1]),
+                                'g'         : parseFloat(parts[2]),
+                                'b'         : parseFloat(parts[3])
+                            }
+
+                            break;
+
+                        case 'translation':
+                        case 'scale':
+                        case 'size':
+                            if (parts.length != 4) {
+                                console.warn('Invalid vector format detected for ' + fieldName);
+                                break;
+                            }
+
+                            property = {
+                                'x'         : parseFloat(parts[1]),
+                                'y'         : parseFloat(parts[2]),
+                                'z'         : parseFloat(parts[3])
+                            }
+
+                            break;
+
+                        case 'radius':
+                        case 'topRadius':
+                        case 'bottomRadius':
+                        case 'height':
+                        case 'transparency':
+                        case 'shininess':
+                        case 'ambientIntensity':
+                            if (parts.length != 2) {
+                                console.warn('Invalid single float value specification detected for ' + fieldName);
+                                break;
+                            }
+
+                            property = parseFloat(parts[1]);
+
+                            break;
+
+                        case 'rotation':
+                            if (parts.length != 5) {
+                                console.warn('Invalid quaternion format detected for ' + fieldName);
+                                break;
+                            }
+
+                            property = {
+                                'x'         : parseFloat(parts[1]),
+                                'y'         : parseFloat(parts[2]),
+                                'z'         : parseFloat(parts[3]),
+                                'w'         : parseFloat(parts[4])
+                            }
+
+                            break;
+
+                        case 'ccw':
+                        case 'solid':
+                        case 'colorPerVertex':
+                        case 'convex':
+                            if (parts.length != 2) {
+                                console.warn('Invalid format detected for ' + fieldName);
+                                break;
+                            }
+
+                            property = parts[1] === 'TRUE' ? true : false;
+
+                            break;
+                    }
+
+                    node[fieldName] = property;
+                }
+
+                return property;
+            };
 
 
 			var getTree = function ( lines ) {
 			var getTree = function ( lines ) {
 
 
 				var tree = { 'string': 'Scene', children: [] };
 				var tree = { 'string': 'Scene', children: [] };
 				var current = tree;
 				var current = tree;
                 var matches;
                 var matches;
+                var specification;
 
 
 				for ( var i = 0; i < lines.length; i ++ ) {
 				for ( var i = 0; i < lines.length; i ++ ) {
 
 
@@ -65,6 +446,13 @@ THREE.VRMLLoader.prototype = {
                         continue;
                         continue;
                     }
                     }
 
 
+                    line = line.trim();
+
+                    // skip empty lines
+                    if (line === '') {
+                        continue;
+                    }
+
 					if ( /#/.exec( line ) ) {
 					if ( /#/.exec( line ) ) {
 
 
                         var parts = line.split('#');
                         var parts = line.split('#');
@@ -75,16 +463,22 @@ THREE.VRMLLoader.prototype = {
                         // well, let's also keep the comment
                         // well, let's also keep the comment
                         comment = parts[1];
                         comment = parts[1];
 					}
 					}
-                    // todo: add collection like coordIndex and colorIndex who are delimited by [ ]
+
                     if ( matches = /([^\s]*){1}\s?{/.exec( line ) ) { // first subpattern should match the Node name
                     if ( matches = /([^\s]*){1}\s?{/.exec( line ) ) { // first subpattern should match the Node name
 
 
-						var block = { 'nodeType' : matches[1], 'string': line, 'parent': current, 'children': [],'comment' : comment };
+						var block = { 'nodeType' : matches[1], 'string': line, 'parent': current, 'children': [],'comment' : comment};
 						current.children.push( block );
 						current.children.push( block );
 						current = block;
 						current = block;
 
 
 						if ( /}/.exec( line ) ) {
 						if ( /}/.exec( line ) ) {
+                            // example: geometry Box { size 1 1 1 } # all on the same line
+                            specification = /{(.*)}/.exec( line )[ 1 ];
+
+                            // todo: remove once new parsing is complete?
+							block.children.push( specification );
+
+                            parseProperty(current, specification);
 
 
-							block.children.push( /{(.*)}/.exec( line )[ 1 ] );
 							current = current.parent;
 							current = current.parent;
 
 
 						}
 						}
@@ -95,6 +489,8 @@ THREE.VRMLLoader.prototype = {
 
 
 					} else if ( line !== '' ) {
 					} else if ( line !== '' ) {
 
 
+                        parseProperty(current, line);
+                        // todo: remove once new parsing is complete? we still do not parse geometry and appearance the new way
                         current.children.push( line );
                         current.children.push( line );
 
 
 					}
 					}
@@ -102,14 +498,8 @@ THREE.VRMLLoader.prototype = {
 				}
 				}
 
 
                 return tree;
                 return tree;
-
 			}
 			}
 
 
-			var defines = {};
-			var float_pattern = /\s+([\d|\.|\+|\-|e]+)/;
-			var float3_pattern = /\s+([\d|\.|\+|\-|e]+),?\s+([\d|\.|\+|\-|e]+),?\s+([\d|\.|\+|\-|e]+)/;
-			var float4_pattern = /\s+([\d|\.|\+|\-|e]+),?\s+([\d|\.|\+|\-|e]+),?\s+([\d|\.|\+|\-|e]+),?\s+([\d|\.|\+|\-|e]+)/;
-
 			var parseNode = function ( data, parent ) {
 			var parseNode = function ( data, parent ) {
 
 
 				// console.log( data );
 				// console.log( data );
@@ -121,20 +511,25 @@ THREE.VRMLLoader.prototype = {
                         var defineKey = /USE\s+?(\w+)/.exec( data )[ 1 ];
                         var defineKey = /USE\s+?(\w+)/.exec( data )[ 1 ];
 
 
                         if (undefined == defines[defineKey]) {
                         if (undefined == defines[defineKey]) {
-                            debugger;
                             console.warn(defineKey + ' is not defined.');
                             console.warn(defineKey + ' is not defined.');
-
                         } else {
                         } else {
 
 
                             if ( /appearance/.exec( data ) && defineKey ) {
                             if ( /appearance/.exec( data ) && defineKey ) {
 
 
-                                parent.material = defines[ defineKey].clone();
+                                parent.material = defines[ defineKey ].clone();
 
 
                             } else if ( /geometry/.exec( data ) && defineKey ) {
                             } else if ( /geometry/.exec( data ) && defineKey ) {
 
 
-                                parent.geometry = defines[ defineKey].clone();
+                                parent.geometry = defines[ defineKey ].clone();
+
+                                // the solid property is not cloned with clone(), is only needed for VRML loading, so we need to transfer it
+                                if (undefined !== defines[ defineKey ].solid && defines[ defineKey ].solid === false) {
+                                    parent.geometry.solid = false;
+                                    parent.material.side = THREE.DoubleSide;
+                                }
 
 
                             } else if (defineKey){
                             } else if (defineKey){
+
                                 var object = defines[ defineKey ].clone();
                                 var object = defines[ defineKey ].clone();
                                 parent.add( object );
                                 parent.add( object );
 
 
@@ -150,222 +545,183 @@ THREE.VRMLLoader.prototype = {
 
 
 				var object = parent;
 				var object = parent;
 
 
-				if ( /Transform/.exec( data.string ) || /Group/.exec( data.string ) ) {
+				if ( 'Transform' === data.nodeType || 'Group' === data.nodeType ) {
+
 					object = new THREE.Object3D();
 					object = new THREE.Object3D();
 
 
 					if ( /DEF/.exec( data.string ) ) {
 					if ( /DEF/.exec( data.string ) ) {
-
 						object.name = /DEF\s+(\w+)/.exec( data.string )[ 1 ];
 						object.name = /DEF\s+(\w+)/.exec( data.string )[ 1 ];
 						defines[ object.name ] = object;
 						defines[ object.name ] = object;
-
 					}
 					}
 
 
-					for ( var i = 0, j = data.children.length; i < j; i ++ ) {
+                    if ( undefined !== data['translation'] ) {
 
 
-						var child = data.children[ i ];
-
-						if ( /translation/.exec( child ) ) {
-
-							var result = float3_pattern.exec( child );
+                        var t = data.translation;
 
 
-							object.position.set(
-								parseFloat( result[ 1 ] ),
-								parseFloat( result[ 2 ] ),
-								parseFloat( result[ 3 ] )
-							);
+                        object.position.set(t.x, t.y, t.z);
 
 
-						} else if ( /rotation/.exec( child ) ) {
+                    }
 
 
-							var result = float4_pattern.exec( child );
+                    if ( undefined !== data.rotation ) {
 
 
-                            var quaternion = new THREE.Quaternion();
+                        var r = data.rotation;
 
 
-                            var x =  parseFloat( result[ 1 ] );
-                            var y = parseFloat(result[ 2 ]);
-                            var z = parseFloat(result[ 3 ]);
-                            var w = parseFloat(result[ 4 ]);
+                        object.quaternion.setFromAxisAngle( new THREE.Vector3( r.x, r.y, r.z ), r.w );
 
 
-                            object.quaternion.setFromAxisAngle( new THREE.Vector3( x, y, z), w );
-						} else if ( /scale/.exec( child ) ) {
+                    }
 
 
-							var result = float3_pattern.exec( child );
+                    if ( undefined !== data.scale ) {
 
 
-							object.scale.set(
-								parseFloat( result[ 1 ] ),
-								parseFloat( result[ 2 ] ),
-								parseFloat( result[ 3 ] )
-							);
+                        var s = data.scale;
 
 
-						}
+                        object.scale.set( s.x, s.y, s.z );
 
 
-					}
+                    }
 
 
 					parent.add( object );
 					parent.add( object );
 
 
-				} else if ( /Shape/.exec( data.string ) ) {
+				} else if ( 'Shape' === data.nodeType ) {
 
 
 					object = new THREE.Mesh();
 					object = new THREE.Mesh();
 
 
 					if ( /DEF/.exec( data.string ) ) {
 					if ( /DEF/.exec( data.string ) ) {
+
 						object.name = /DEF (\w+)/.exec( data.string )[ 1 ];
 						object.name = /DEF (\w+)/.exec( data.string )[ 1 ];
+
 						defines[ object.name ] = object;
 						defines[ object.name ] = object;
 					}
 					}
 
 
 					parent.add( object );
 					parent.add( object );
 
 
-				} else if ( /geometry/.exec( data.string ) ) {
-
-					if ( /Box/.exec( data.string ) ) {
-
-						var width = 1, height = 1, depth = 1;
+				} else if ( 'Background' === data.nodeType ) {
 
 
-						for ( var i = 0, j = data.children.length; i < j; i ++ ) {
+                    var segments = 20;
 
 
-							var child = data.children[ i ];
+                    // sky (full sphere):
+                    var radius = 2e4;
 
 
-							if ( /size/.exec( child ) ) {
+                    var skyGeometry = new THREE.SphereGeometry( radius, segments, segments );
 
 
-								var result = float3_pattern.exec( child );
+                    var skyMaterial = new THREE.MeshBasicMaterial( { color: 'white', vertexColors: THREE.VertexColors, shading: THREE.NoShading } );
 
 
-								width = parseFloat( result[ 1 ] );
-								height = parseFloat( result[ 2 ] );
-								depth = parseFloat( result[ 3 ] );
+                    skyMaterial.side = THREE.BackSide;
 
 
-							}
+                    skyMaterial.fog = false;
 
 
-						}
+                    skyMaterial.color = new THREE.Color();
 
 
-						parent.geometry = new THREE.CubeGeometry( width, height, depth );
+                    paintFaces( skyGeometry, radius, data.skyAngle, data.skyColor, true );
 
 
-					} else if ( /Cylinder/.exec( data.string ) ) {
+                    var sky = new THREE.Mesh( skyGeometry, skyMaterial );
 
 
-						var radius = 1, height = 1;
+                    scene.add( sky );
 
 
-						for ( var i = 0, j = data.children.length; i < j; i ++ ) {
+                    // ground (half sphere):
 
 
-							var child = data.children[ i ];
+                    radius = 1.2e4;
 
 
-							if ( /radius/.exec( child ) ) {
+                    var groundGeometry = new THREE.SphereGeometry( radius, segments, segments, 0, 2 * Math.PI, 0.5 * Math.PI, 1.5 * Math.PI );
 
 
-								radius = parseFloat( float_pattern.exec( child )[ 1 ] );
+                    var groundMaterial = new THREE.MeshBasicMaterial( { color: 'white', vertexColors: THREE.VertexColors, shading: THREE.NoShading } );
 
 
-							} else if ( /height/.exec( child ) ) {
+                    groundMaterial.side = THREE.BackSide;
 
 
-								height = parseFloat( float_pattern.exec( child )[ 1 ] );
+                    groundMaterial.fog = false;
 
 
-							}
+                    groundMaterial.color = new THREE.Color();
 
 
-						}
+                    paintFaces( groundGeometry, radius, data.groundAngle, data.groundColor, false );
 
 
-						parent.geometry = new THREE.CylinderGeometry( radius, radius, height );
+                    var ground = new THREE.Mesh( groundGeometry, groundMaterial );
 
 
-					} else if ( /Cone/.exec( data.string ) ) {
+                    scene.add( ground );
 
 
-						var topRadius = 0, bottomRadius = 1, height = 1;
-
-						for ( var i = 0, j = data.children.length; i < j; i ++ ) {
+				} else if ( /geometry/.exec( data.string ) ) {
 
 
-							var child = data.children[ i ];
+					if ( 'Box' === data.nodeType ) {
 
 
-							if ( /bottomRadius/.exec( child ) ) {
+                        var s = data.size;
 
 
-								bottomRadius = parseFloat( float_pattern.exec( child )[ 1 ] );
+						parent.geometry = new THREE.CubeGeometry( s.x, s.y, s.z );
 
 
-							} else if ( /height/.exec( child ) ) {
+					} else if ( 'Cylinder' === data.nodeType ) {
 
 
-								height = parseFloat( float_pattern.exec( child )[ 1 ] );
+						parent.geometry = new THREE.CylinderGeometry( data.radius, data.radius, data.height );
 
 
-							}
-
-						}
+					} else if ( 'Cone' === data.nodeType ) {
 
 
-						parent.geometry = new THREE.CylinderGeometry( topRadius, bottomRadius, height );
+						parent.geometry = new THREE.CylinderGeometry( data.topRadius, data.bottomRadius, data.height );
 
 
-					} else if ( /Sphere/.exec( data.string ) ) {
+					} else if ( 'Sphere' === data.nodeType ) {
 
 
-						var result = /radius\s+([\d|\.|\+|\-|e]+)/.exec( data.children[ 0 ] );
+						parent.geometry = new THREE.SphereGeometry( data.radius );
 
 
-						parent.geometry = new THREE.SphereGeometry( parseFloat( result[ 1 ] ) );
-
-					} else if ( /IndexedFaceSet/.exec( data.string ) ) {
+					} else if ( 'IndexedFaceSet' === data.nodeType ) {
 
 
                         var geometry = new THREE.Geometry();
                         var geometry = new THREE.Geometry();
 
 
-                        var isRecordingCoordinates = false;
+                        var indexes;
 
 
-                        for (var i = 0, j = data.children.length; i < j; i++) {
+                        for ( var i = 0, j = data.children.length; i < j; i++ ) {
 
 
-                            var child = data.children[i];
+                            var child = data.children[ i ];
 
 
-                            var result;
                             var vec;
                             var vec;
 
 
-                            if ( /Coordinate/.exec (child.string)) {
-
-                                for (var k = 0, l = child.children.length; k < l; k++) {
+                            if ( 'Coordinate' === child.nodeType ) {
 
 
-                                    var point = child.children[k];
+                                for ( var k = 0, l = child.points.length; k < l; k++ ) {
 
 
-                                    if (null != (result = float3_pattern.exec(point))) {
+                                    var point = child.points[ k ];
 
 
-                                        vec = new THREE.Vector3(
-                                            parseFloat(result[1]),
-                                            parseFloat(result[2]),
-                                            parseFloat(result[3])
-                                        );
+                                    vec = new THREE.Vector3( point.x, point.y, point.z );
 
 
-                                        geometry.vertices.push( vec );
-                                    }
+                                    geometry.vertices.push( vec );
                                 }
                                 }
-                            }
 
 
-                            if (/coordIndex/.exec(child)) {
-                                isRecordingCoordinates = true;
+                                break;
                             }
                             }
+                        }
 
 
-                            var coordIndex = false;
-                            var points =  [];
-                            var skip = 0;
-                            var regex = /(-?\d+)/g;
-                            // read this: http://math.hws.edu/eck/cs424/notes2013/16_Threejs_Advanced.html
-                            while ( isRecordingCoordinates && null != (coordIndex = regex.exec(child) ) ) {
-                                // parse coordIndex lines
-                                coordIndex = parseInt(coordIndex, 10);
-
-                                points.push(coordIndex);
-
-                                // -1 indicates end of face points
-                                if (coordIndex === -1) {
-                                    // reset the collection
-                                    points = [];
-                                }
+                        var skip = 0;
+
+                        // read this: http://math.hws.edu/eck/cs424/notes2013/16_Threejs_Advanced.html
+                        for ( var i = 0, j = data.coordIndex.length; i < j; i++ ) {
 
 
-                                // vrml support multipoint indexed face sets (more then 3 vertices). You must calculate the composing triangles here
+                            indexes = data.coordIndex[i];
 
 
-                                skip = points.length -3;
-                                skip = skip < 0 ? 0 : skip;
+                            // vrml support multipoint indexed face sets (more then 3 vertices). You must calculate the composing triangles here
+                            skip = 0;
 
 
-                                // Face3 only works with triangles, but IndexedFaceSet allows shapes with more then three vertices, build them of triangles
-                                if (points.length >= 3) {
-                                    var face = new THREE.Face3(
-                                        points[0],
-                                        points[skip + 1],
-                                        points[skip + 2],
-                                        null // normal, will be added later
-                                        // todo: pass in the color
-                                    );
+                            // todo: this is the time to check if the faces are ordered ccw or not (cw)
 
 
-                                    geometry.faces.push(face);
+                            // Face3 only works with triangles, but IndexedFaceSet allows shapes with more then three vertices, build them of triangles
+                            while ( indexes.length >= 3 && skip < ( indexes.length -2 ) ) {
 
 
-                                    }
+                                var face = new THREE.Face3(
+                                    indexes[0],
+                                    indexes[skip + 1],
+                                    indexes[skip + 2],
+                                    null // normal, will be added later
+                                    // todo: pass in the color, if a color index is present
+                                );
+
+                                skip++;
+
+                                geometry.faces.push( face );
 
 
                             }
                             }
 
 
-                            // stop recording if a ] is encountered after recording was turned on
-                            isRecordingCoordinates = (isRecordingCoordinates && null === (/]/.exec(child) ) );
 
 
                         }
                         }
 
 
+                        if ( false === data.solid ) {
+                            parent.material.side = THREE.DoubleSide;
+                        }
+
+                        // we need to store it on the geometry for use with defines
+                        geometry.solid = data.solid;
+
                         geometry.computeFaceNormals();
                         geometry.computeFaceNormals();
                         //geometry.computeVertexNormals(); // does not show
                         //geometry.computeVertexNormals(); // does not show
                         geometry.computeBoundingSphere();
                         geometry.computeBoundingSphere();
@@ -387,55 +743,43 @@ THREE.VRMLLoader.prototype = {
 
 
 						var child = data.children[ i ];
 						var child = data.children[ i ];
 
 
-						if ( /Material/.exec( child.string ) ) {
-
+						if ( 'Material' === child.nodeType ) {
 							var material = new THREE.MeshPhongMaterial();
 							var material = new THREE.MeshPhongMaterial();
-                            material.side = THREE.DoubleSide;
 
 
-							for ( var j = 0; j < child.children.length; j ++ ) {
+                            if ( undefined !== child.diffuseColor ) {
 
 
-								var parameter = child.children[ j ];
+                                var d = child.diffuseColor;
 
 
-								if ( /diffuseColor/.exec( parameter ) ) {
+                                material.color.setRGB( d.r, d.g, d.b );
 
 
-									var result = float3_pattern.exec( parameter );
+                            }
 
 
-									material.color.setRGB(
-										parseFloat( result[ 1 ] ),
-										parseFloat( result[ 2 ] ),
-										parseFloat( result[ 3 ] )
-									);
+                            if ( undefined !== child.emissiveColor ) {
 
 
-								} else if ( /emissiveColor/.exec( parameter ) ) {
+                                var e = child.emissiveColor;
 
 
-									var result = float3_pattern.exec( parameter );
+                                material.emissive.setRGB( e.r, e.g, e.b );
 
 
-									material.emissive.setRGB(
-										parseFloat( result[ 1 ] ),
-										parseFloat( result[ 2 ] ),
-										parseFloat( result[ 3 ] )
-									);
+                            }
 
 
-								} else if ( /specularColor/.exec( parameter ) ) {
+                            if ( undefined !== child.specularColor ) {
 
 
-									var result = float3_pattern.exec( parameter );
+                                var s = child.specularColor;
 
 
-									material.specular.setRGB(
-										parseFloat( result[ 1 ] ),
-										parseFloat( result[ 2 ] ),
-										parseFloat( result[ 3 ] )
-									);
+                                material.specular.setRGB( s.r, s.g, s.b );
 
 
-								} else if ( /transparency/.exec( parameter ) ) {
+                            }
 
 
-									var result = /\s+([\d|\.|\+|\-|e]+)/.exec( parameter );
-                                    // transparency is opposite of opacity
-									material.opacity = Math.abs( 1 - parseFloat( result[ 1 ] ) );
-									material.transparent = true;
+                            if ( undefined !== child.transparency ) {
 
 
-								}
+                                var t = child.transparency;
 
 
-							}
+                                // transparency is opposite of opacity
+                                material.opacity = Math.abs( 1 - t );
+
+                                material.transparent = true;
+
+                            }
 
 
 							if ( /DEF/.exec( data.string ) ) {
 							if ( /DEF/.exec( data.string ) ) {
 
 
@@ -447,6 +791,8 @@ THREE.VRMLLoader.prototype = {
 
 
 							parent.material = material;
 							parent.material = material;
 
 
+                            // material found, stop looping
+                            break;
 						}
 						}
 
 
 					}
 					}
@@ -472,6 +818,7 @@ THREE.VRMLLoader.prototype = {
 		var scene = new THREE.Scene();
 		var scene = new THREE.Scene();
 
 
 		var lines = data.split( '\n' );
 		var lines = data.split( '\n' );
+
 		var header = lines.shift();
 		var header = lines.shift();
 
 
 		if ( /V1.0/.exec( header ) ) {
 		if ( /V1.0/.exec( header ) ) {
@@ -491,3 +838,4 @@ THREE.VRMLLoader.prototype = {
 };
 };
 
 
 THREE.EventDispatcher.prototype.apply( THREE.VRMLLoader.prototype );
 THREE.EventDispatcher.prototype.apply( THREE.VRMLLoader.prototype );
+