浏览代码

Fixed doublesided material on non solid USE(d) IndexedFaceSets

Bart McLeod 11 年之前
父节点
当前提交
1ba3c34082
共有 1 个文件被更改,包括 305 次插入190 次删除
  1. 305 190
      examples/js/loaders/VRMLLoader.js

+ 305 - 190
examples/js/loaders/VRMLLoader.js

@@ -8,6 +8,14 @@ THREE.VRMLLoader.prototype = {
 
 	constructor: THREE.VRMLLoader,
 
+    isRecordingPoints: false,
+
+    isRecordingFaces: false,
+
+    points: [],
+
+    indexes : [],
+
 	load: function ( url, callback ) {
 
 		var scope = this;
@@ -47,12 +55,192 @@ THREE.VRMLLoader.prototype = {
 		};
 
 		var parseV2 = function ( lines, scene ) {
+            var defines = {};
+            var float3_pattern = /([\d\.\+\-e]+),?\s+([\d\.\+\-e]+),?\s+([\d\.\+\-e]+)/;
+
+            var parseProperty = function (node, line) {
+
+                var parts = [];
+                var part;
+                var property = {};
+                var fieldName;
+
+                /**
+                 * Expression for matching relevant information, such as a name or value, but not the separators
+                 * @type {RegExp}
+                 */
+                var regex = /[^\s,\[\]]+/g;
+                var point;
+                var index;
+
+                while (null != ( part = regex.exec(line) ) ) {
+                    parts.push(part[0]);
+                }
+
+                fieldName = parts[0];
+
+                if (fieldName === 'point') {
+                    // start recording points
+                    this.isRecordingPoints = true;
+                    this.points = [];
+                }
+
+                if (fieldName === 'coordIndex') {
+                    // start recording faces
+                    this.isRecordingFaces = true;
+                    this.indexes = [];
+                }
+
+                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 ( 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 tree = { 'string': 'Scene', children: [] };
 				var current = tree;
                 var matches;
+                var specification;
 
 				for ( var i = 0; i < lines.length; i ++ ) {
 
@@ -65,6 +253,13 @@ THREE.VRMLLoader.prototype = {
                         continue;
                     }
 
+                    line = line.trim();
+
+                    // skip empty lines
+                    if (line === '') {
+                        continue;
+                    }
+
 					if ( /#/.exec( line ) ) {
 
                         var parts = line.split('#');
@@ -75,16 +270,22 @@ THREE.VRMLLoader.prototype = {
                         // well, let's also keep the comment
                         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
 
-						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 = block;
 
 						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;
 
 						}
@@ -95,6 +296,8 @@ THREE.VRMLLoader.prototype = {
 
 					} else if ( line !== '' ) {
 
+                        parseProperty(current, line);
+                        // todo: remove once new parsing is complete?
                         current.children.push( line );
 
 					}
@@ -102,14 +305,8 @@ THREE.VRMLLoader.prototype = {
 				}
 
                 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 ) {
 
 				// console.log( data );
@@ -121,20 +318,25 @@ THREE.VRMLLoader.prototype = {
                         var defineKey = /USE\s+?(\w+)/.exec( data )[ 1 ];
 
                         if (undefined == defines[defineKey]) {
-                            debugger;
                             console.warn(defineKey + ' is not defined.');
-
                         } else {
 
                             if ( /appearance/.exec( data ) && defineKey ) {
 
-                                parent.material = defines[ defineKey].clone();
+                                parent.material = defines[ defineKey ].clone();
 
                             } 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){
+
                                 var object = defines[ defineKey ].clone();
                                 parent.add( object );
 
@@ -150,59 +352,42 @@ THREE.VRMLLoader.prototype = {
 
 				var object = parent;
 
-				if ( /Transform/.exec( data.string ) || /Group/.exec( data.string ) ) {
+				if ( 'Transform' === data.nodeType || 'Group' === data.nodeType ) {
+
 					object = new THREE.Object3D();
 
 					if ( /DEF/.exec( data.string ) ) {
-
 						object.name = /DEF\s+(\w+)/.exec( data.string )[ 1 ];
 						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 t = data.translation;
 
-							var result = float3_pattern.exec( child );
+                        object.position.set(t.x, t.y, t.z);
 
-							object.position.set(
-								parseFloat( result[ 1 ] ),
-								parseFloat( result[ 2 ] ),
-								parseFloat( result[ 3 ] )
-							);
-
-						} 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 );
 
-				} else if ( /Shape/.exec( data.string ) ) {
+				} else if ( 'Shape' === data.nodeType ) {
 
 					object = new THREE.Mesh();
 
@@ -213,159 +398,95 @@ THREE.VRMLLoader.prototype = {
 
 					parent.add( object );
 
-				} else if ( /geometry/.exec( data.string ) ) {
-
-					if ( /Box/.exec( data.string ) ) {
-
-						var width = 1, height = 1, depth = 1;
-
-						for ( var i = 0, j = data.children.length; i < j; i ++ ) {
-
-							var child = data.children[ i ];
-
-							if ( /size/.exec( child ) ) {
-
-								var result = float3_pattern.exec( child );
-
-								width = parseFloat( result[ 1 ] );
-								height = parseFloat( result[ 2 ] );
-								depth = parseFloat( result[ 3 ] );
-
-							}
-
-						}
-
-						parent.geometry = new THREE.CubeGeometry( width, height, depth );
-
-					} else if ( /Cylinder/.exec( data.string ) ) {
-
-						var radius = 1, height = 1;
-
-						for ( var i = 0, j = data.children.length; i < j; i ++ ) {
-
-							var child = data.children[ i ];
+				} else if ( 'Background' === data.nodeType ) {
 
-							if ( /radius/.exec( child ) ) {
+                    console.warn('Implement hemisphere light here');
 
-								radius = parseFloat( float_pattern.exec( child )[ 1 ] );
-
-							} else if ( /height/.exec( child ) ) {
-
-								height = parseFloat( float_pattern.exec( child )[ 1 ] );
-
-							}
-
-						}
-
-						parent.geometry = new THREE.CylinderGeometry( radius, radius, height );
-
-					} else if ( /Cone/.exec( data.string ) ) {
-
-						var topRadius = 0, bottomRadius = 1, height = 1;
-
-						for ( var i = 0, j = data.children.length; i < j; i ++ ) {
-
-							var child = data.children[ i ];
-
-							if ( /bottomRadius/.exec( child ) ) {
+				} else if ( /geometry/.exec( data.string ) ) {
 
-								bottomRadius = parseFloat( float_pattern.exec( child )[ 1 ] );
+					if ( 'Box' === data.nodeType ) {
 
-							} else if ( /height/.exec( child ) ) {
+                        var s = data.size;
 
-								height = parseFloat( float_pattern.exec( child )[ 1 ] );
+						parent.geometry = new THREE.CubeGeometry( s.x, s.y, s.z );
 
-							}
+					} else if ( 'Cylinder' === data.nodeType ) {
 
-						}
+						parent.geometry = new THREE.CylinderGeometry( data.radius, data.radius, data.height );
 
-						parent.geometry = new THREE.CylinderGeometry( topRadius, bottomRadius, height );
+					} else if ( 'Cone' === data.nodeType ) {
 
-					} else if ( /Sphere/.exec( data.string ) ) {
+						parent.geometry = new THREE.CylinderGeometry( data.topRadius, data.bottomRadius, data.height );
 
-						var result = /radius\s+([\d|\.|\+|\-|e]+)/.exec( data.children[ 0 ] );
+					} else if ( 'Sphere' === data.nodeType ) {
 
-						parent.geometry = new THREE.SphereGeometry( parseFloat( result[ 1 ] ) );
+						parent.geometry = new THREE.SphereGeometry( data.radius );
 
-					} else if ( /IndexedFaceSet/.exec( data.string ) ) {
+					} else if ( 'IndexedFaceSet' === data.nodeType ) {
 
                         var geometry = new THREE.Geometry();
 
-                        var isRecordingCoordinates = false;
+                        var indexes;
 
                         for (var i = 0, j = data.children.length; i < j; i++) {
 
                             var child = data.children[i];
 
-                            var result;
                             var vec;
 
-                            if ( /Coordinate/.exec (child.string)) {
+                            if ( 'Coordinate' === child.nodeType ) {
 
-                                for (var k = 0, l = child.children.length; k < l; k++) {
+                                for (var k = 0, l = child.points.length; k < l; k++) {
 
-                                    var point = child.children[k];
+                                    var point = child.points[k];
 
-                                    if (null != (result = float3_pattern.exec(point))) {
+                                    vec = new THREE.Vector3(point.x, point.y, point.z);
 
-                                        vec = new THREE.Vector3(
-                                            parseFloat(result[1]),
-                                            parseFloat(result[2]),
-                                            parseFloat(result[3])
-                                        );
-
-                                        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++) {
+
+                            indexes = data.coordIndex[i];
+
+                            // vrml support multipoint indexed face sets (more then 3 vertices). You must calculate the composing triangles here
+                            skip = 0;
 
-                                // vrml support multipoint indexed face sets (more then 3 vertices). You must calculate the composing triangles here
+                            // todo: this is the time to check if the faces are ordered ccw or not (cw)
 
-                                skip = points.length -3;
-                                skip = skip < 0 ? 0 : skip;
+                            // 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) ) {
 
-                                // 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
-                                    );
+                                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
+                                );
 
-                                    geometry.faces.push(face);
+                                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.computeVertexNormals(); // does not show
                         geometry.computeBoundingSphere();
@@ -387,55 +508,42 @@ THREE.VRMLLoader.prototype = {
 
 						var child = data.children[ i ];
 
-						if ( /Material/.exec( child.string ) ) {
-
+						if ( 'Material' === child.nodeType ) {
 							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 ) ) {
 
@@ -445,8 +553,15 @@ THREE.VRMLLoader.prototype = {
 
 							}
 
+                            // todo: below does not work, but we should find a way to make it work (for USE(d) geometries (IndexedFaceSets) that are marked as solid)
+                            if (undefined !== parent.geometry.solid && false === parent.geometry.solid) {
+                                material.side = THREE.DoubleSide;
+                            }
+
 							parent.material = material;
 
+                            // material found, stop looping
+                            break;
 						}
 
 					}