VRMLLoader.js 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140
  1. ( function () {
  2. class VRMLLoader extends THREE.Loader {
  3. constructor( manager ) {
  4. super( manager );
  5. // dependency check
  6. if ( typeof chevrotain === 'undefined' ) {
  7. // eslint-disable-line no-undef
  8. throw Error( 'THREE.VRMLLoader: External library chevrotain.min.js required.' );
  9. }
  10. }
  11. load( url, onLoad, onProgress, onError ) {
  12. const scope = this;
  13. const path = scope.path === '' ? THREE.LoaderUtils.extractUrlBase( url ) : scope.path;
  14. const loader = new THREE.FileLoader( scope.manager );
  15. loader.setPath( scope.path );
  16. loader.setRequestHeader( scope.requestHeader );
  17. loader.setWithCredentials( scope.withCredentials );
  18. loader.load( url, function ( text ) {
  19. try {
  20. onLoad( scope.parse( text, path ) );
  21. } catch ( e ) {
  22. if ( onError ) {
  23. onError( e );
  24. } else {
  25. console.error( e );
  26. }
  27. scope.manager.itemError( url );
  28. }
  29. }, onProgress, onError );
  30. }
  31. parse( data, path ) {
  32. const nodeMap = {};
  33. function generateVRMLTree( data ) {
  34. // create lexer, parser and visitor
  35. const tokenData = createTokens();
  36. const lexer = new VRMLLexer( tokenData.tokens );
  37. const parser = new VRMLParser( tokenData.tokenVocabulary );
  38. const visitor = createVisitor( parser.getBaseCstVisitorConstructor() );
  39. // lexing
  40. const lexingResult = lexer.lex( data );
  41. parser.input = lexingResult.tokens;
  42. // parsing
  43. const cstOutput = parser.vrml();
  44. if ( parser.errors.length > 0 ) {
  45. console.error( parser.errors );
  46. throw Error( 'THREE.VRMLLoader: Parsing errors detected.' );
  47. }
  48. // actions
  49. const ast = visitor.visit( cstOutput );
  50. return ast;
  51. }
  52. function createTokens() {
  53. const createToken = chevrotain.createToken; // eslint-disable-line no-undef
  54. // from http://gun.teipir.gr/VRML-amgem/spec/part1/concepts.html#SyntaxBasics
  55. const RouteIdentifier = createToken( {
  56. name: 'RouteIdentifier',
  57. pattern: /[^\x30-\x39\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d][^\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d]*[\.][^\x30-\x39\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d][^\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d]*/
  58. } );
  59. const Identifier = createToken( {
  60. name: 'Identifier',
  61. pattern: /[^\x30-\x39\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d][^\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d]*/,
  62. longer_alt: RouteIdentifier
  63. } );
  64. // from http://gun.teipir.gr/VRML-amgem/spec/part1/nodesRef.html
  65. const nodeTypes = [ 'Anchor', 'Billboard', 'Collision', 'Group', 'Transform',
  66. // grouping nodes
  67. 'Inline', 'LOD', 'Switch',
  68. // special groups
  69. 'AudioClip', 'DirectionalLight', 'PointLight', 'Script', 'Shape', 'Sound', 'SpotLight', 'WorldInfo',
  70. // common nodes
  71. 'CylinderSensor', 'PlaneSensor', 'ProximitySensor', 'SphereSensor', 'TimeSensor', 'TouchSensor', 'VisibilitySensor',
  72. // sensors
  73. 'Box', 'Cone', 'Cylinder', 'ElevationGrid', 'Extrusion', 'IndexedFaceSet', 'IndexedLineSet', 'PointSet', 'Sphere',
  74. // geometries
  75. 'Color', 'Coordinate', 'Normal', 'TextureCoordinate',
  76. // geometric properties
  77. 'Appearance', 'FontStyle', 'ImageTexture', 'Material', 'MovieTexture', 'PixelTexture', 'TextureTransform',
  78. // appearance
  79. 'ColorInterpolator', 'CoordinateInterpolator', 'NormalInterpolator', 'OrientationInterpolator', 'PositionInterpolator', 'ScalarInterpolator',
  80. // interpolators
  81. 'Background', 'Fog', 'NavigationInfo', 'Viewpoint',
  82. // bindable nodes
  83. 'Text' // Text must be placed at the end of the regex so there are no matches for TextureTransform and TextureCoordinate
  84. ];
  85. //
  86. const Version = createToken( {
  87. name: 'Version',
  88. pattern: /#VRML.*/,
  89. longer_alt: Identifier
  90. } );
  91. const NodeName = createToken( {
  92. name: 'NodeName',
  93. pattern: new RegExp( nodeTypes.join( '|' ) ),
  94. longer_alt: Identifier
  95. } );
  96. const DEF = createToken( {
  97. name: 'DEF',
  98. pattern: /DEF/,
  99. longer_alt: Identifier
  100. } );
  101. const USE = createToken( {
  102. name: 'USE',
  103. pattern: /USE/,
  104. longer_alt: Identifier
  105. } );
  106. const ROUTE = createToken( {
  107. name: 'ROUTE',
  108. pattern: /ROUTE/,
  109. longer_alt: Identifier
  110. } );
  111. const TO = createToken( {
  112. name: 'TO',
  113. pattern: /TO/,
  114. longer_alt: Identifier
  115. } );
  116. //
  117. const StringLiteral = createToken( {
  118. name: 'StringLiteral',
  119. pattern: /"(?:[^\\"\n\r]|\\[bfnrtv"\\/]|\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])*"/
  120. } );
  121. const HexLiteral = createToken( {
  122. name: 'HexLiteral',
  123. pattern: /0[xX][0-9a-fA-F]+/
  124. } );
  125. const NumberLiteral = createToken( {
  126. name: 'NumberLiteral',
  127. pattern: /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/
  128. } );
  129. const TrueLiteral = createToken( {
  130. name: 'TrueLiteral',
  131. pattern: /TRUE/
  132. } );
  133. const FalseLiteral = createToken( {
  134. name: 'FalseLiteral',
  135. pattern: /FALSE/
  136. } );
  137. const NullLiteral = createToken( {
  138. name: 'NullLiteral',
  139. pattern: /NULL/
  140. } );
  141. const LSquare = createToken( {
  142. name: 'LSquare',
  143. pattern: /\[/
  144. } );
  145. const RSquare = createToken( {
  146. name: 'RSquare',
  147. pattern: /]/
  148. } );
  149. const LCurly = createToken( {
  150. name: 'LCurly',
  151. pattern: /{/
  152. } );
  153. const RCurly = createToken( {
  154. name: 'RCurly',
  155. pattern: /}/
  156. } );
  157. const Comment = createToken( {
  158. name: 'Comment',
  159. pattern: /#.*/,
  160. group: chevrotain.Lexer.SKIPPED // eslint-disable-line no-undef
  161. } );
  162. // commas, blanks, tabs, newlines and carriage returns are whitespace characters wherever they appear outside of string fields
  163. const WhiteSpace = createToken( {
  164. name: 'WhiteSpace',
  165. pattern: /[ ,\s]/,
  166. group: chevrotain.Lexer.SKIPPED // eslint-disable-line no-undef
  167. } );
  168. const tokens = [ WhiteSpace,
  169. // keywords appear before the Identifier
  170. NodeName, DEF, USE, ROUTE, TO, TrueLiteral, FalseLiteral, NullLiteral,
  171. // the Identifier must appear after the keywords because all keywords are valid identifiers
  172. Version, Identifier, RouteIdentifier, StringLiteral, HexLiteral, NumberLiteral, LSquare, RSquare, LCurly, RCurly, Comment ];
  173. const tokenVocabulary = {};
  174. for ( let i = 0, l = tokens.length; i < l; i ++ ) {
  175. const token = tokens[ i ];
  176. tokenVocabulary[ token.name ] = token;
  177. }
  178. return {
  179. tokens: tokens,
  180. tokenVocabulary: tokenVocabulary
  181. };
  182. }
  183. function createVisitor( BaseVRMLVisitor ) {
  184. // the visitor is created dynmaically based on the given base class
  185. class VRMLToASTVisitor extends BaseVRMLVisitor {
  186. constructor() {
  187. super();
  188. this.validateVisitor();
  189. }
  190. vrml( ctx ) {
  191. const data = {
  192. version: this.visit( ctx.version ),
  193. nodes: [],
  194. routes: []
  195. };
  196. for ( let i = 0, l = ctx.node.length; i < l; i ++ ) {
  197. const node = ctx.node[ i ];
  198. data.nodes.push( this.visit( node ) );
  199. }
  200. if ( ctx.route ) {
  201. for ( let i = 0, l = ctx.route.length; i < l; i ++ ) {
  202. const route = ctx.route[ i ];
  203. data.routes.push( this.visit( route ) );
  204. }
  205. }
  206. return data;
  207. }
  208. version( ctx ) {
  209. return ctx.Version[ 0 ].image;
  210. }
  211. node( ctx ) {
  212. const data = {
  213. name: ctx.NodeName[ 0 ].image,
  214. fields: []
  215. };
  216. if ( ctx.field ) {
  217. for ( let i = 0, l = ctx.field.length; i < l; i ++ ) {
  218. const field = ctx.field[ i ];
  219. data.fields.push( this.visit( field ) );
  220. }
  221. }
  222. // DEF
  223. if ( ctx.def ) {
  224. data.DEF = this.visit( ctx.def[ 0 ] );
  225. }
  226. return data;
  227. }
  228. field( ctx ) {
  229. const data = {
  230. name: ctx.Identifier[ 0 ].image,
  231. type: null,
  232. values: null
  233. };
  234. let result;
  235. // SFValue
  236. if ( ctx.singleFieldValue ) {
  237. result = this.visit( ctx.singleFieldValue[ 0 ] );
  238. }
  239. // MFValue
  240. if ( ctx.multiFieldValue ) {
  241. result = this.visit( ctx.multiFieldValue[ 0 ] );
  242. }
  243. data.type = result.type;
  244. data.values = result.values;
  245. return data;
  246. }
  247. def( ctx ) {
  248. return ( ctx.Identifier || ctx.NodeName )[ 0 ].image;
  249. }
  250. use( ctx ) {
  251. return {
  252. USE: ( ctx.Identifier || ctx.NodeName )[ 0 ].image
  253. };
  254. }
  255. singleFieldValue( ctx ) {
  256. return processField( this, ctx );
  257. }
  258. multiFieldValue( ctx ) {
  259. return processField( this, ctx );
  260. }
  261. route( ctx ) {
  262. const data = {
  263. FROM: ctx.RouteIdentifier[ 0 ].image,
  264. TO: ctx.RouteIdentifier[ 1 ].image
  265. };
  266. return data;
  267. }
  268. }
  269. function processField( scope, ctx ) {
  270. const field = {
  271. type: null,
  272. values: []
  273. };
  274. if ( ctx.node ) {
  275. field.type = 'node';
  276. for ( let i = 0, l = ctx.node.length; i < l; i ++ ) {
  277. const node = ctx.node[ i ];
  278. field.values.push( scope.visit( node ) );
  279. }
  280. }
  281. if ( ctx.use ) {
  282. field.type = 'use';
  283. for ( let i = 0, l = ctx.use.length; i < l; i ++ ) {
  284. const use = ctx.use[ i ];
  285. field.values.push( scope.visit( use ) );
  286. }
  287. }
  288. if ( ctx.StringLiteral ) {
  289. field.type = 'string';
  290. for ( let i = 0, l = ctx.StringLiteral.length; i < l; i ++ ) {
  291. const stringLiteral = ctx.StringLiteral[ i ];
  292. field.values.push( stringLiteral.image.replace( /'|"/g, '' ) );
  293. }
  294. }
  295. if ( ctx.NumberLiteral ) {
  296. field.type = 'number';
  297. for ( let i = 0, l = ctx.NumberLiteral.length; i < l; i ++ ) {
  298. const numberLiteral = ctx.NumberLiteral[ i ];
  299. field.values.push( parseFloat( numberLiteral.image ) );
  300. }
  301. }
  302. if ( ctx.HexLiteral ) {
  303. field.type = 'hex';
  304. for ( let i = 0, l = ctx.HexLiteral.length; i < l; i ++ ) {
  305. const hexLiteral = ctx.HexLiteral[ i ];
  306. field.values.push( hexLiteral.image );
  307. }
  308. }
  309. if ( ctx.TrueLiteral ) {
  310. field.type = 'boolean';
  311. for ( let i = 0, l = ctx.TrueLiteral.length; i < l; i ++ ) {
  312. const trueLiteral = ctx.TrueLiteral[ i ];
  313. if ( trueLiteral.image === 'TRUE' ) field.values.push( true );
  314. }
  315. }
  316. if ( ctx.FalseLiteral ) {
  317. field.type = 'boolean';
  318. for ( let i = 0, l = ctx.FalseLiteral.length; i < l; i ++ ) {
  319. const falseLiteral = ctx.FalseLiteral[ i ];
  320. if ( falseLiteral.image === 'FALSE' ) field.values.push( false );
  321. }
  322. }
  323. if ( ctx.NullLiteral ) {
  324. field.type = 'null';
  325. ctx.NullLiteral.forEach( function () {
  326. field.values.push( null );
  327. } );
  328. }
  329. return field;
  330. }
  331. return new VRMLToASTVisitor();
  332. }
  333. function parseTree( tree ) {
  334. // console.log( JSON.stringify( tree, null, 2 ) );
  335. const nodes = tree.nodes;
  336. const scene = new THREE.Scene();
  337. // first iteration: build nodemap based on DEF statements
  338. for ( let i = 0, l = nodes.length; i < l; i ++ ) {
  339. const node = nodes[ i ];
  340. buildNodeMap( node );
  341. }
  342. // second iteration: build nodes
  343. for ( let i = 0, l = nodes.length; i < l; i ++ ) {
  344. const node = nodes[ i ];
  345. const object = getNode( node );
  346. if ( object instanceof THREE.Object3D ) scene.add( object );
  347. if ( node.name === 'WorldInfo' ) scene.userData.worldInfo = object;
  348. }
  349. return scene;
  350. }
  351. function buildNodeMap( node ) {
  352. if ( node.DEF ) {
  353. nodeMap[ node.DEF ] = node;
  354. }
  355. const fields = node.fields;
  356. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  357. const field = fields[ i ];
  358. if ( field.type === 'node' ) {
  359. const fieldValues = field.values;
  360. for ( let j = 0, jl = fieldValues.length; j < jl; j ++ ) {
  361. buildNodeMap( fieldValues[ j ] );
  362. }
  363. }
  364. }
  365. }
  366. function getNode( node ) {
  367. // handle case where a node refers to a different one
  368. if ( node.USE ) {
  369. return resolveUSE( node.USE );
  370. }
  371. if ( node.build !== undefined ) return node.build;
  372. node.build = buildNode( node );
  373. return node.build;
  374. }
  375. // node builder
  376. function buildNode( node ) {
  377. const nodeName = node.name;
  378. let build;
  379. switch ( nodeName ) {
  380. case 'Anchor':
  381. case 'Group':
  382. case 'Transform':
  383. case 'Collision':
  384. build = buildGroupingNode( node );
  385. break;
  386. case 'Background':
  387. build = buildBackgroundNode( node );
  388. break;
  389. case 'Shape':
  390. build = buildShapeNode( node );
  391. break;
  392. case 'Appearance':
  393. build = buildAppearanceNode( node );
  394. break;
  395. case 'Material':
  396. build = buildMaterialNode( node );
  397. break;
  398. case 'ImageTexture':
  399. build = buildImageTextureNode( node );
  400. break;
  401. case 'PixelTexture':
  402. build = buildPixelTextureNode( node );
  403. break;
  404. case 'TextureTransform':
  405. build = buildTextureTransformNode( node );
  406. break;
  407. case 'IndexedFaceSet':
  408. build = buildIndexedFaceSetNode( node );
  409. break;
  410. case 'IndexedLineSet':
  411. build = buildIndexedLineSetNode( node );
  412. break;
  413. case 'PointSet':
  414. build = buildPointSetNode( node );
  415. break;
  416. case 'Box':
  417. build = buildBoxNode( node );
  418. break;
  419. case 'Cone':
  420. build = buildConeNode( node );
  421. break;
  422. case 'Cylinder':
  423. build = buildCylinderNode( node );
  424. break;
  425. case 'Sphere':
  426. build = buildSphereNode( node );
  427. break;
  428. case 'ElevationGrid':
  429. build = buildElevationGridNode( node );
  430. break;
  431. case 'Extrusion':
  432. build = buildExtrusionNode( node );
  433. break;
  434. case 'Color':
  435. case 'Coordinate':
  436. case 'Normal':
  437. case 'TextureCoordinate':
  438. build = buildGeometricNode( node );
  439. break;
  440. case 'WorldInfo':
  441. build = buildWorldInfoNode( node );
  442. break;
  443. case 'Billboard':
  444. case 'Inline':
  445. case 'LOD':
  446. case 'Switch':
  447. case 'AudioClip':
  448. case 'DirectionalLight':
  449. case 'PointLight':
  450. case 'Script':
  451. case 'Sound':
  452. case 'SpotLight':
  453. case 'CylinderSensor':
  454. case 'PlaneSensor':
  455. case 'ProximitySensor':
  456. case 'SphereSensor':
  457. case 'TimeSensor':
  458. case 'TouchSensor':
  459. case 'VisibilitySensor':
  460. case 'Text':
  461. case 'FontStyle':
  462. case 'MovieTexture':
  463. case 'ColorInterpolator':
  464. case 'CoordinateInterpolator':
  465. case 'NormalInterpolator':
  466. case 'OrientationInterpolator':
  467. case 'PositionInterpolator':
  468. case 'ScalarInterpolator':
  469. case 'Fog':
  470. case 'NavigationInfo':
  471. case 'Viewpoint':
  472. // node not supported yet
  473. break;
  474. default:
  475. console.warn( 'THREE.VRMLLoader: Unknown node:', nodeName );
  476. break;
  477. }
  478. if ( build !== undefined && node.DEF !== undefined && build.hasOwnProperty( 'name' ) === true ) {
  479. build.name = node.DEF;
  480. }
  481. return build;
  482. }
  483. function buildGroupingNode( node ) {
  484. const object = new THREE.Group();
  485. //
  486. const fields = node.fields;
  487. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  488. const field = fields[ i ];
  489. const fieldName = field.name;
  490. const fieldValues = field.values;
  491. switch ( fieldName ) {
  492. case 'bboxCenter':
  493. // field not supported
  494. break;
  495. case 'bboxSize':
  496. // field not supported
  497. break;
  498. case 'center':
  499. // field not supported
  500. break;
  501. case 'children':
  502. parseFieldChildren( fieldValues, object );
  503. break;
  504. case 'description':
  505. // field not supported
  506. break;
  507. case 'collide':
  508. // field not supported
  509. break;
  510. case 'parameter':
  511. // field not supported
  512. break;
  513. case 'rotation':
  514. const axis = new THREE.Vector3( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] );
  515. const angle = fieldValues[ 3 ];
  516. object.quaternion.setFromAxisAngle( axis, angle );
  517. break;
  518. case 'scale':
  519. object.scale.set( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] );
  520. break;
  521. case 'scaleOrientation':
  522. // field not supported
  523. break;
  524. case 'translation':
  525. object.position.set( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] );
  526. break;
  527. case 'proxy':
  528. // field not supported
  529. break;
  530. case 'url':
  531. // field not supported
  532. break;
  533. default:
  534. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  535. break;
  536. }
  537. }
  538. return object;
  539. }
  540. function buildBackgroundNode( node ) {
  541. const group = new THREE.Group();
  542. let groundAngle, groundColor;
  543. let skyAngle, skyColor;
  544. const fields = node.fields;
  545. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  546. const field = fields[ i ];
  547. const fieldName = field.name;
  548. const fieldValues = field.values;
  549. switch ( fieldName ) {
  550. case 'groundAngle':
  551. groundAngle = fieldValues;
  552. break;
  553. case 'groundColor':
  554. groundColor = fieldValues;
  555. break;
  556. case 'backUrl':
  557. // field not supported
  558. break;
  559. case 'bottomUrl':
  560. // field not supported
  561. break;
  562. case 'frontUrl':
  563. // field not supported
  564. break;
  565. case 'leftUrl':
  566. // field not supported
  567. break;
  568. case 'rightUrl':
  569. // field not supported
  570. break;
  571. case 'topUrl':
  572. // field not supported
  573. break;
  574. case 'skyAngle':
  575. skyAngle = fieldValues;
  576. break;
  577. case 'skyColor':
  578. skyColor = fieldValues;
  579. break;
  580. default:
  581. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  582. break;
  583. }
  584. }
  585. const radius = 10000;
  586. // sky
  587. if ( skyColor ) {
  588. const skyGeometry = new THREE.SphereGeometry( radius, 32, 16 );
  589. const skyMaterial = new THREE.MeshBasicMaterial( {
  590. fog: false,
  591. side: THREE.BackSide,
  592. depthWrite: false,
  593. depthTest: false
  594. } );
  595. if ( skyColor.length > 3 ) {
  596. paintFaces( skyGeometry, radius, skyAngle, toColorArray( skyColor ), true );
  597. skyMaterial.vertexColors = true;
  598. } else {
  599. skyMaterial.color.setRGB( skyColor[ 0 ], skyColor[ 1 ], skyColor[ 2 ] );
  600. }
  601. const sky = new THREE.Mesh( skyGeometry, skyMaterial );
  602. group.add( sky );
  603. }
  604. // ground
  605. if ( groundColor ) {
  606. if ( groundColor.length > 0 ) {
  607. const groundGeometry = new THREE.SphereGeometry( radius, 32, 16, 0, 2 * Math.PI, 0.5 * Math.PI, 1.5 * Math.PI );
  608. const groundMaterial = new THREE.MeshBasicMaterial( {
  609. fog: false,
  610. side: THREE.BackSide,
  611. vertexColors: true,
  612. depthWrite: false,
  613. depthTest: false
  614. } );
  615. paintFaces( groundGeometry, radius, groundAngle, toColorArray( groundColor ), false );
  616. const ground = new THREE.Mesh( groundGeometry, groundMaterial );
  617. group.add( ground );
  618. }
  619. }
  620. // render background group first
  621. group.renderOrder = - Infinity;
  622. return group;
  623. }
  624. function buildShapeNode( node ) {
  625. const fields = node.fields;
  626. // if the appearance field is NULL or unspecified, lighting is off and the unlit object color is (0, 0, 0)
  627. let material = new THREE.MeshBasicMaterial( {
  628. color: 0x000000
  629. } );
  630. let geometry;
  631. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  632. const field = fields[ i ];
  633. const fieldName = field.name;
  634. const fieldValues = field.values;
  635. switch ( fieldName ) {
  636. case 'appearance':
  637. if ( fieldValues[ 0 ] !== null ) {
  638. material = getNode( fieldValues[ 0 ] );
  639. }
  640. break;
  641. case 'geometry':
  642. if ( fieldValues[ 0 ] !== null ) {
  643. geometry = getNode( fieldValues[ 0 ] );
  644. }
  645. break;
  646. default:
  647. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  648. break;
  649. }
  650. }
  651. // build 3D object
  652. let object;
  653. if ( geometry && geometry.attributes.position ) {
  654. const type = geometry._type;
  655. if ( type === 'points' ) {
  656. // points
  657. const pointsMaterial = new THREE.PointsMaterial( {
  658. color: 0xffffff
  659. } );
  660. if ( geometry.attributes.color !== undefined ) {
  661. pointsMaterial.vertexColors = true;
  662. } else {
  663. // if the color field is NULL and there is a material defined for the appearance affecting this PointSet, then use the emissiveColor of the material to draw the points
  664. if ( material.isMeshPhongMaterial ) {
  665. pointsMaterial.color.copy( material.emissive );
  666. }
  667. }
  668. object = new THREE.Points( geometry, pointsMaterial );
  669. } else if ( type === 'line' ) {
  670. // lines
  671. const lineMaterial = new THREE.LineBasicMaterial( {
  672. color: 0xffffff
  673. } );
  674. if ( geometry.attributes.color !== undefined ) {
  675. lineMaterial.vertexColors = true;
  676. } else {
  677. // if the color field is NULL and there is a material defined for the appearance affecting this IndexedLineSet, then use the emissiveColor of the material to draw the lines
  678. if ( material.isMeshPhongMaterial ) {
  679. lineMaterial.color.copy( material.emissive );
  680. }
  681. }
  682. object = new THREE.LineSegments( geometry, lineMaterial );
  683. } else {
  684. // consider meshes
  685. // check "solid" hint (it's placed in the geometry but affects the material)
  686. if ( geometry._solid !== undefined ) {
  687. material.side = geometry._solid ? THREE.FrontSide : THREE.DoubleSide;
  688. }
  689. // check for vertex colors
  690. if ( geometry.attributes.color !== undefined ) {
  691. material.vertexColors = true;
  692. }
  693. object = new THREE.Mesh( geometry, material );
  694. }
  695. } else {
  696. object = new THREE.Object3D();
  697. // if the geometry field is NULL or no vertices are defined the object is not drawn
  698. object.visible = false;
  699. }
  700. return object;
  701. }
  702. function buildAppearanceNode( node ) {
  703. let material = new THREE.MeshPhongMaterial();
  704. let transformData;
  705. const fields = node.fields;
  706. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  707. const field = fields[ i ];
  708. const fieldName = field.name;
  709. const fieldValues = field.values;
  710. switch ( fieldName ) {
  711. case 'material':
  712. if ( fieldValues[ 0 ] !== null ) {
  713. const materialData = getNode( fieldValues[ 0 ] );
  714. if ( materialData.diffuseColor ) material.color.copy( materialData.diffuseColor );
  715. if ( materialData.emissiveColor ) material.emissive.copy( materialData.emissiveColor );
  716. if ( materialData.shininess ) material.shininess = materialData.shininess;
  717. if ( materialData.specularColor ) material.specular.copy( materialData.specularColor );
  718. if ( materialData.transparency ) material.opacity = 1 - materialData.transparency;
  719. if ( materialData.transparency > 0 ) material.transparent = true;
  720. } else {
  721. // if the material field is NULL or unspecified, lighting is off and the unlit object color is (0, 0, 0)
  722. material = new THREE.MeshBasicMaterial( {
  723. color: 0x000000
  724. } );
  725. }
  726. break;
  727. case 'texture':
  728. const textureNode = fieldValues[ 0 ];
  729. if ( textureNode !== null ) {
  730. if ( textureNode.name === 'ImageTexture' || textureNode.name === 'PixelTexture' ) {
  731. material.map = getNode( textureNode );
  732. } else {
  733. // MovieTexture not supported yet
  734. }
  735. }
  736. break;
  737. case 'textureTransform':
  738. if ( fieldValues[ 0 ] !== null ) {
  739. transformData = getNode( fieldValues[ 0 ] );
  740. }
  741. break;
  742. default:
  743. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  744. break;
  745. }
  746. }
  747. // only apply texture transform data if a texture was defined
  748. if ( material.map ) {
  749. // respect VRML lighting model
  750. if ( material.map.__type ) {
  751. switch ( material.map.__type ) {
  752. case TEXTURE_TYPE.INTENSITY_ALPHA:
  753. material.opacity = 1; // ignore transparency
  754. break;
  755. case TEXTURE_TYPE.RGB:
  756. material.color.set( 0xffffff ); // ignore material color
  757. break;
  758. case TEXTURE_TYPE.RGBA:
  759. material.color.set( 0xffffff ); // ignore material color
  760. material.opacity = 1; // ignore transparency
  761. break;
  762. default:
  763. }
  764. delete material.map.__type;
  765. }
  766. // apply texture transform
  767. if ( transformData ) {
  768. material.map.center.copy( transformData.center );
  769. material.map.rotation = transformData.rotation;
  770. material.map.repeat.copy( transformData.scale );
  771. material.map.offset.copy( transformData.translation );
  772. }
  773. }
  774. return material;
  775. }
  776. function buildMaterialNode( node ) {
  777. const materialData = {};
  778. const fields = node.fields;
  779. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  780. const field = fields[ i ];
  781. const fieldName = field.name;
  782. const fieldValues = field.values;
  783. switch ( fieldName ) {
  784. case 'ambientIntensity':
  785. // field not supported
  786. break;
  787. case 'diffuseColor':
  788. materialData.diffuseColor = new THREE.Color( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] );
  789. break;
  790. case 'emissiveColor':
  791. materialData.emissiveColor = new THREE.Color( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] );
  792. break;
  793. case 'shininess':
  794. materialData.shininess = fieldValues[ 0 ];
  795. break;
  796. case 'specularColor':
  797. materialData.emissiveColor = new THREE.Color( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] );
  798. break;
  799. case 'transparency':
  800. materialData.transparency = fieldValues[ 0 ];
  801. break;
  802. default:
  803. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  804. break;
  805. }
  806. }
  807. return materialData;
  808. }
  809. function parseHexColor( hex, textureType, color ) {
  810. let value;
  811. switch ( textureType ) {
  812. case TEXTURE_TYPE.INTENSITY:
  813. // Intensity texture: A one-component image specifies one-byte hexadecimal or integer values representing the intensity of the image
  814. value = parseInt( hex );
  815. color.r = value;
  816. color.g = value;
  817. color.b = value;
  818. color.a = 1;
  819. break;
  820. case TEXTURE_TYPE.INTENSITY_ALPHA:
  821. // Intensity+Alpha texture: A two-component image specifies the intensity in the first (high) byte and the alpha opacity in the second (low) byte.
  822. value = parseInt( '0x' + hex.substring( 2, 4 ) );
  823. color.r = value;
  824. color.g = value;
  825. color.b = value;
  826. color.a = parseInt( '0x' + hex.substring( 4, 6 ) );
  827. break;
  828. case TEXTURE_TYPE.RGB:
  829. // RGB texture: Pixels in a three-component image specify the red component in the first (high) byte, followed by the green and blue components
  830. color.r = parseInt( '0x' + hex.substring( 2, 4 ) );
  831. color.g = parseInt( '0x' + hex.substring( 4, 6 ) );
  832. color.b = parseInt( '0x' + hex.substring( 6, 8 ) );
  833. color.a = 1;
  834. break;
  835. case TEXTURE_TYPE.RGBA:
  836. // RGBA texture: Four-component images specify the alpha opacity byte after red/green/blue
  837. color.r = parseInt( '0x' + hex.substring( 2, 4 ) );
  838. color.g = parseInt( '0x' + hex.substring( 4, 6 ) );
  839. color.b = parseInt( '0x' + hex.substring( 6, 8 ) );
  840. color.a = parseInt( '0x' + hex.substring( 8, 10 ) );
  841. break;
  842. default:
  843. }
  844. }
  845. function getTextureType( num_components ) {
  846. let type;
  847. switch ( num_components ) {
  848. case 1:
  849. type = TEXTURE_TYPE.INTENSITY;
  850. break;
  851. case 2:
  852. type = TEXTURE_TYPE.INTENSITY_ALPHA;
  853. break;
  854. case 3:
  855. type = TEXTURE_TYPE.RGB;
  856. break;
  857. case 4:
  858. type = TEXTURE_TYPE.RGBA;
  859. break;
  860. default:
  861. }
  862. return type;
  863. }
  864. function buildPixelTextureNode( node ) {
  865. let texture;
  866. let wrapS = THREE.RepeatWrapping;
  867. let wrapT = THREE.RepeatWrapping;
  868. const fields = node.fields;
  869. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  870. const field = fields[ i ];
  871. const fieldName = field.name;
  872. const fieldValues = field.values;
  873. switch ( fieldName ) {
  874. case 'image':
  875. const width = fieldValues[ 0 ];
  876. const height = fieldValues[ 1 ];
  877. const num_components = fieldValues[ 2 ];
  878. const textureType = getTextureType( num_components );
  879. const data = new Uint8Array( 4 * width * height );
  880. const color = {
  881. r: 0,
  882. g: 0,
  883. b: 0,
  884. a: 0
  885. };
  886. for ( let j = 3, k = 0, jl = fieldValues.length; j < jl; j ++, k ++ ) {
  887. parseHexColor( fieldValues[ j ], textureType, color );
  888. const stride = k * 4;
  889. data[ stride + 0 ] = color.r;
  890. data[ stride + 1 ] = color.g;
  891. data[ stride + 2 ] = color.b;
  892. data[ stride + 3 ] = color.a;
  893. }
  894. texture = new THREE.DataTexture( data, width, height );
  895. texture.needsUpdate = true;
  896. texture.__type = textureType; // needed for material modifications
  897. break;
  898. case 'repeatS':
  899. if ( fieldValues[ 0 ] === false ) wrapS = THREE.ClampToEdgeWrapping;
  900. break;
  901. case 'repeatT':
  902. if ( fieldValues[ 0 ] === false ) wrapT = THREE.ClampToEdgeWrapping;
  903. break;
  904. default:
  905. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  906. break;
  907. }
  908. }
  909. if ( texture ) {
  910. texture.wrapS = wrapS;
  911. texture.wrapT = wrapT;
  912. }
  913. return texture;
  914. }
  915. function buildImageTextureNode( node ) {
  916. let texture;
  917. let wrapS = THREE.RepeatWrapping;
  918. let wrapT = THREE.RepeatWrapping;
  919. const fields = node.fields;
  920. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  921. const field = fields[ i ];
  922. const fieldName = field.name;
  923. const fieldValues = field.values;
  924. switch ( fieldName ) {
  925. case 'url':
  926. const url = fieldValues[ 0 ];
  927. if ( url ) texture = textureLoader.load( url );
  928. break;
  929. case 'repeatS':
  930. if ( fieldValues[ 0 ] === false ) wrapS = THREE.ClampToEdgeWrapping;
  931. break;
  932. case 'repeatT':
  933. if ( fieldValues[ 0 ] === false ) wrapT = THREE.ClampToEdgeWrapping;
  934. break;
  935. default:
  936. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  937. break;
  938. }
  939. }
  940. if ( texture ) {
  941. texture.wrapS = wrapS;
  942. texture.wrapT = wrapT;
  943. }
  944. return texture;
  945. }
  946. function buildTextureTransformNode( node ) {
  947. const transformData = {
  948. center: new THREE.Vector2(),
  949. rotation: new THREE.Vector2(),
  950. scale: new THREE.Vector2(),
  951. translation: new THREE.Vector2()
  952. };
  953. const fields = node.fields;
  954. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  955. const field = fields[ i ];
  956. const fieldName = field.name;
  957. const fieldValues = field.values;
  958. switch ( fieldName ) {
  959. case 'center':
  960. transformData.center.set( fieldValues[ 0 ], fieldValues[ 1 ] );
  961. break;
  962. case 'rotation':
  963. transformData.rotation = fieldValues[ 0 ];
  964. break;
  965. case 'scale':
  966. transformData.scale.set( fieldValues[ 0 ], fieldValues[ 1 ] );
  967. break;
  968. case 'translation':
  969. transformData.translation.set( fieldValues[ 0 ], fieldValues[ 1 ] );
  970. break;
  971. default:
  972. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  973. break;
  974. }
  975. }
  976. return transformData;
  977. }
  978. function buildGeometricNode( node ) {
  979. return node.fields[ 0 ].values;
  980. }
  981. function buildWorldInfoNode( node ) {
  982. const worldInfo = {};
  983. const fields = node.fields;
  984. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  985. const field = fields[ i ];
  986. const fieldName = field.name;
  987. const fieldValues = field.values;
  988. switch ( fieldName ) {
  989. case 'title':
  990. worldInfo.title = fieldValues[ 0 ];
  991. break;
  992. case 'info':
  993. worldInfo.info = fieldValues;
  994. break;
  995. default:
  996. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  997. break;
  998. }
  999. }
  1000. return worldInfo;
  1001. }
  1002. function buildIndexedFaceSetNode( node ) {
  1003. let color, coord, normal, texCoord;
  1004. let ccw = true,
  1005. solid = true,
  1006. creaseAngle = 0;
  1007. let colorIndex, coordIndex, normalIndex, texCoordIndex;
  1008. let colorPerVertex = true,
  1009. normalPerVertex = true;
  1010. const fields = node.fields;
  1011. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  1012. const field = fields[ i ];
  1013. const fieldName = field.name;
  1014. const fieldValues = field.values;
  1015. switch ( fieldName ) {
  1016. case 'color':
  1017. const colorNode = fieldValues[ 0 ];
  1018. if ( colorNode !== null ) {
  1019. color = getNode( colorNode );
  1020. }
  1021. break;
  1022. case 'coord':
  1023. const coordNode = fieldValues[ 0 ];
  1024. if ( coordNode !== null ) {
  1025. coord = getNode( coordNode );
  1026. }
  1027. break;
  1028. case 'normal':
  1029. const normalNode = fieldValues[ 0 ];
  1030. if ( normalNode !== null ) {
  1031. normal = getNode( normalNode );
  1032. }
  1033. break;
  1034. case 'texCoord':
  1035. const texCoordNode = fieldValues[ 0 ];
  1036. if ( texCoordNode !== null ) {
  1037. texCoord = getNode( texCoordNode );
  1038. }
  1039. break;
  1040. case 'ccw':
  1041. ccw = fieldValues[ 0 ];
  1042. break;
  1043. case 'colorIndex':
  1044. colorIndex = fieldValues;
  1045. break;
  1046. case 'colorPerVertex':
  1047. colorPerVertex = fieldValues[ 0 ];
  1048. break;
  1049. case 'convex':
  1050. // field not supported
  1051. break;
  1052. case 'coordIndex':
  1053. coordIndex = fieldValues;
  1054. break;
  1055. case 'creaseAngle':
  1056. creaseAngle = fieldValues[ 0 ];
  1057. break;
  1058. case 'normalIndex':
  1059. normalIndex = fieldValues;
  1060. break;
  1061. case 'normalPerVertex':
  1062. normalPerVertex = fieldValues[ 0 ];
  1063. break;
  1064. case 'solid':
  1065. solid = fieldValues[ 0 ];
  1066. break;
  1067. case 'texCoordIndex':
  1068. texCoordIndex = fieldValues;
  1069. break;
  1070. default:
  1071. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  1072. break;
  1073. }
  1074. }
  1075. if ( coordIndex === undefined ) {
  1076. console.warn( 'THREE.VRMLLoader: Missing coordIndex.' );
  1077. return new THREE.BufferGeometry(); // handle VRML files with incomplete geometry definition
  1078. }
  1079. const triangulatedCoordIndex = triangulateFaceIndex( coordIndex, ccw );
  1080. let colorAttribute;
  1081. let normalAttribute;
  1082. let uvAttribute;
  1083. if ( color ) {
  1084. if ( colorPerVertex === true ) {
  1085. if ( colorIndex && colorIndex.length > 0 ) {
  1086. // if the colorIndex field is not empty, then it is used to choose colors for each vertex of the IndexedFaceSet.
  1087. const triangulatedColorIndex = triangulateFaceIndex( colorIndex, ccw );
  1088. colorAttribute = computeAttributeFromIndexedData( triangulatedCoordIndex, triangulatedColorIndex, color, 3 );
  1089. } else {
  1090. // if the colorIndex field is empty, then the coordIndex field is used to choose colors from the THREE.Color node
  1091. colorAttribute = toNonIndexedAttribute( triangulatedCoordIndex, new THREE.Float32BufferAttribute( color, 3 ) );
  1092. }
  1093. } else {
  1094. if ( colorIndex && colorIndex.length > 0 ) {
  1095. // if the colorIndex field is not empty, then they are used to choose one color for each face of the IndexedFaceSet
  1096. const flattenFaceColors = flattenData( color, colorIndex );
  1097. const triangulatedFaceColors = triangulateFaceData( flattenFaceColors, coordIndex );
  1098. colorAttribute = computeAttributeFromFaceData( triangulatedCoordIndex, triangulatedFaceColors );
  1099. } else {
  1100. // if the colorIndex field is empty, then the color are applied to each face of the IndexedFaceSet in order
  1101. const triangulatedFaceColors = triangulateFaceData( color, coordIndex );
  1102. colorAttribute = computeAttributeFromFaceData( triangulatedCoordIndex, triangulatedFaceColors );
  1103. }
  1104. }
  1105. }
  1106. if ( normal ) {
  1107. if ( normalPerVertex === true ) {
  1108. // consider vertex normals
  1109. if ( normalIndex && normalIndex.length > 0 ) {
  1110. // if the normalIndex field is not empty, then it is used to choose normals for each vertex of the IndexedFaceSet.
  1111. const triangulatedNormalIndex = triangulateFaceIndex( normalIndex, ccw );
  1112. normalAttribute = computeAttributeFromIndexedData( triangulatedCoordIndex, triangulatedNormalIndex, normal, 3 );
  1113. } else {
  1114. // if the normalIndex field is empty, then the coordIndex field is used to choose normals from the Normal node
  1115. normalAttribute = toNonIndexedAttribute( triangulatedCoordIndex, new THREE.Float32BufferAttribute( normal, 3 ) );
  1116. }
  1117. } else {
  1118. // consider face normals
  1119. if ( normalIndex && normalIndex.length > 0 ) {
  1120. // if the normalIndex field is not empty, then they are used to choose one normal for each face of the IndexedFaceSet
  1121. const flattenFaceNormals = flattenData( normal, normalIndex );
  1122. const triangulatedFaceNormals = triangulateFaceData( flattenFaceNormals, coordIndex );
  1123. normalAttribute = computeAttributeFromFaceData( triangulatedCoordIndex, triangulatedFaceNormals );
  1124. } else {
  1125. // if the normalIndex field is empty, then the normals are applied to each face of the IndexedFaceSet in order
  1126. const triangulatedFaceNormals = triangulateFaceData( normal, coordIndex );
  1127. normalAttribute = computeAttributeFromFaceData( triangulatedCoordIndex, triangulatedFaceNormals );
  1128. }
  1129. }
  1130. } else {
  1131. // if the normal field is NULL, then the loader should automatically generate normals, using creaseAngle to determine if and how normals are smoothed across shared vertices
  1132. normalAttribute = computeNormalAttribute( triangulatedCoordIndex, coord, creaseAngle );
  1133. }
  1134. if ( texCoord ) {
  1135. // texture coordinates are always defined on vertex level
  1136. if ( texCoordIndex && texCoordIndex.length > 0 ) {
  1137. // if the texCoordIndex field is not empty, then it is used to choose texture coordinates for each vertex of the IndexedFaceSet.
  1138. const triangulatedTexCoordIndex = triangulateFaceIndex( texCoordIndex, ccw );
  1139. uvAttribute = computeAttributeFromIndexedData( triangulatedCoordIndex, triangulatedTexCoordIndex, texCoord, 2 );
  1140. } else {
  1141. // if the texCoordIndex field is empty, then the coordIndex array is used to choose texture coordinates from the TextureCoordinate node
  1142. uvAttribute = toNonIndexedAttribute( triangulatedCoordIndex, new THREE.Float32BufferAttribute( texCoord, 2 ) );
  1143. }
  1144. }
  1145. const geometry = new THREE.BufferGeometry();
  1146. const positionAttribute = toNonIndexedAttribute( triangulatedCoordIndex, new THREE.Float32BufferAttribute( coord, 3 ) );
  1147. geometry.setAttribute( 'position', positionAttribute );
  1148. geometry.setAttribute( 'normal', normalAttribute );
  1149. // optional attributes
  1150. if ( colorAttribute ) geometry.setAttribute( 'color', colorAttribute );
  1151. if ( uvAttribute ) geometry.setAttribute( 'uv', uvAttribute );
  1152. // "solid" influences the material so let's store it for later use
  1153. geometry._solid = solid;
  1154. geometry._type = 'mesh';
  1155. return geometry;
  1156. }
  1157. function buildIndexedLineSetNode( node ) {
  1158. let color, coord;
  1159. let colorIndex, coordIndex;
  1160. let colorPerVertex = true;
  1161. const fields = node.fields;
  1162. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  1163. const field = fields[ i ];
  1164. const fieldName = field.name;
  1165. const fieldValues = field.values;
  1166. switch ( fieldName ) {
  1167. case 'color':
  1168. const colorNode = fieldValues[ 0 ];
  1169. if ( colorNode !== null ) {
  1170. color = getNode( colorNode );
  1171. }
  1172. break;
  1173. case 'coord':
  1174. const coordNode = fieldValues[ 0 ];
  1175. if ( coordNode !== null ) {
  1176. coord = getNode( coordNode );
  1177. }
  1178. break;
  1179. case 'colorIndex':
  1180. colorIndex = fieldValues;
  1181. break;
  1182. case 'colorPerVertex':
  1183. colorPerVertex = fieldValues[ 0 ];
  1184. break;
  1185. case 'coordIndex':
  1186. coordIndex = fieldValues;
  1187. break;
  1188. default:
  1189. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  1190. break;
  1191. }
  1192. }
  1193. // build lines
  1194. let colorAttribute;
  1195. const expandedLineIndex = expandLineIndex( coordIndex ); // create an index for three.js's linesegment primitive
  1196. if ( color ) {
  1197. if ( colorPerVertex === true ) {
  1198. if ( colorIndex.length > 0 ) {
  1199. // if the colorIndex field is not empty, then one color is used for each polyline of the IndexedLineSet.
  1200. const expandedColorIndex = expandLineIndex( colorIndex ); // compute colors for each line segment (rendering primitve)
  1201. colorAttribute = computeAttributeFromIndexedData( expandedLineIndex, expandedColorIndex, color, 3 ); // compute data on vertex level
  1202. } else {
  1203. // if the colorIndex field is empty, then the colors are applied to each polyline of the IndexedLineSet in order.
  1204. colorAttribute = toNonIndexedAttribute( expandedLineIndex, new THREE.Float32BufferAttribute( color, 3 ) );
  1205. }
  1206. } else {
  1207. if ( colorIndex.length > 0 ) {
  1208. // if the colorIndex field is not empty, then colors are applied to each vertex of the IndexedLineSet
  1209. const flattenLineColors = flattenData( color, colorIndex ); // compute colors for each VRML primitve
  1210. const expandedLineColors = expandLineData( flattenLineColors, coordIndex ); // compute colors for each line segment (rendering primitve)
  1211. colorAttribute = computeAttributeFromLineData( expandedLineIndex, expandedLineColors ); // compute data on vertex level
  1212. } else {
  1213. // if the colorIndex field is empty, then the coordIndex field is used to choose colors from the THREE.Color node
  1214. const expandedLineColors = expandLineData( color, coordIndex ); // compute colors for each line segment (rendering primitve)
  1215. colorAttribute = computeAttributeFromLineData( expandedLineIndex, expandedLineColors ); // compute data on vertex level
  1216. }
  1217. }
  1218. }
  1219. //
  1220. const geometry = new THREE.BufferGeometry();
  1221. const positionAttribute = toNonIndexedAttribute( expandedLineIndex, new THREE.Float32BufferAttribute( coord, 3 ) );
  1222. geometry.setAttribute( 'position', positionAttribute );
  1223. if ( colorAttribute ) geometry.setAttribute( 'color', colorAttribute );
  1224. geometry._type = 'line';
  1225. return geometry;
  1226. }
  1227. function buildPointSetNode( node ) {
  1228. let color, coord;
  1229. const fields = node.fields;
  1230. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  1231. const field = fields[ i ];
  1232. const fieldName = field.name;
  1233. const fieldValues = field.values;
  1234. switch ( fieldName ) {
  1235. case 'color':
  1236. const colorNode = fieldValues[ 0 ];
  1237. if ( colorNode !== null ) {
  1238. color = getNode( colorNode );
  1239. }
  1240. break;
  1241. case 'coord':
  1242. const coordNode = fieldValues[ 0 ];
  1243. if ( coordNode !== null ) {
  1244. coord = getNode( coordNode );
  1245. }
  1246. break;
  1247. default:
  1248. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  1249. break;
  1250. }
  1251. }
  1252. const geometry = new THREE.BufferGeometry();
  1253. geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( coord, 3 ) );
  1254. if ( color ) geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( color, 3 ) );
  1255. geometry._type = 'points';
  1256. return geometry;
  1257. }
  1258. function buildBoxNode( node ) {
  1259. const size = new THREE.Vector3( 2, 2, 2 );
  1260. const fields = node.fields;
  1261. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  1262. const field = fields[ i ];
  1263. const fieldName = field.name;
  1264. const fieldValues = field.values;
  1265. switch ( fieldName ) {
  1266. case 'size':
  1267. size.x = fieldValues[ 0 ];
  1268. size.y = fieldValues[ 1 ];
  1269. size.z = fieldValues[ 2 ];
  1270. break;
  1271. default:
  1272. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  1273. break;
  1274. }
  1275. }
  1276. const geometry = new THREE.BoxGeometry( size.x, size.y, size.z );
  1277. return geometry;
  1278. }
  1279. function buildConeNode( node ) {
  1280. let radius = 1,
  1281. height = 2,
  1282. openEnded = false;
  1283. const fields = node.fields;
  1284. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  1285. const field = fields[ i ];
  1286. const fieldName = field.name;
  1287. const fieldValues = field.values;
  1288. switch ( fieldName ) {
  1289. case 'bottom':
  1290. openEnded = ! fieldValues[ 0 ];
  1291. break;
  1292. case 'bottomRadius':
  1293. radius = fieldValues[ 0 ];
  1294. break;
  1295. case 'height':
  1296. height = fieldValues[ 0 ];
  1297. break;
  1298. case 'side':
  1299. // field not supported
  1300. break;
  1301. default:
  1302. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  1303. break;
  1304. }
  1305. }
  1306. const geometry = new THREE.ConeGeometry( radius, height, 16, 1, openEnded );
  1307. return geometry;
  1308. }
  1309. function buildCylinderNode( node ) {
  1310. let radius = 1,
  1311. height = 2;
  1312. const fields = node.fields;
  1313. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  1314. const field = fields[ i ];
  1315. const fieldName = field.name;
  1316. const fieldValues = field.values;
  1317. switch ( fieldName ) {
  1318. case 'bottom':
  1319. // field not supported
  1320. break;
  1321. case 'radius':
  1322. radius = fieldValues[ 0 ];
  1323. break;
  1324. case 'height':
  1325. height = fieldValues[ 0 ];
  1326. break;
  1327. case 'side':
  1328. // field not supported
  1329. break;
  1330. case 'top':
  1331. // field not supported
  1332. break;
  1333. default:
  1334. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  1335. break;
  1336. }
  1337. }
  1338. const geometry = new THREE.CylinderGeometry( radius, radius, height, 16, 1 );
  1339. return geometry;
  1340. }
  1341. function buildSphereNode( node ) {
  1342. let radius = 1;
  1343. const fields = node.fields;
  1344. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  1345. const field = fields[ i ];
  1346. const fieldName = field.name;
  1347. const fieldValues = field.values;
  1348. switch ( fieldName ) {
  1349. case 'radius':
  1350. radius = fieldValues[ 0 ];
  1351. break;
  1352. default:
  1353. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  1354. break;
  1355. }
  1356. }
  1357. const geometry = new THREE.SphereGeometry( radius, 16, 16 );
  1358. return geometry;
  1359. }
  1360. function buildElevationGridNode( node ) {
  1361. let color;
  1362. let normal;
  1363. let texCoord;
  1364. let height;
  1365. let colorPerVertex = true;
  1366. let normalPerVertex = true;
  1367. let solid = true;
  1368. let ccw = true;
  1369. let creaseAngle = 0;
  1370. let xDimension = 2;
  1371. let zDimension = 2;
  1372. let xSpacing = 1;
  1373. let zSpacing = 1;
  1374. const fields = node.fields;
  1375. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  1376. const field = fields[ i ];
  1377. const fieldName = field.name;
  1378. const fieldValues = field.values;
  1379. switch ( fieldName ) {
  1380. case 'color':
  1381. const colorNode = fieldValues[ 0 ];
  1382. if ( colorNode !== null ) {
  1383. color = getNode( colorNode );
  1384. }
  1385. break;
  1386. case 'normal':
  1387. const normalNode = fieldValues[ 0 ];
  1388. if ( normalNode !== null ) {
  1389. normal = getNode( normalNode );
  1390. }
  1391. break;
  1392. case 'texCoord':
  1393. const texCoordNode = fieldValues[ 0 ];
  1394. if ( texCoordNode !== null ) {
  1395. texCoord = getNode( texCoordNode );
  1396. }
  1397. break;
  1398. case 'height':
  1399. height = fieldValues;
  1400. break;
  1401. case 'ccw':
  1402. ccw = fieldValues[ 0 ];
  1403. break;
  1404. case 'colorPerVertex':
  1405. colorPerVertex = fieldValues[ 0 ];
  1406. break;
  1407. case 'creaseAngle':
  1408. creaseAngle = fieldValues[ 0 ];
  1409. break;
  1410. case 'normalPerVertex':
  1411. normalPerVertex = fieldValues[ 0 ];
  1412. break;
  1413. case 'solid':
  1414. solid = fieldValues[ 0 ];
  1415. break;
  1416. case 'xDimension':
  1417. xDimension = fieldValues[ 0 ];
  1418. break;
  1419. case 'xSpacing':
  1420. xSpacing = fieldValues[ 0 ];
  1421. break;
  1422. case 'zDimension':
  1423. zDimension = fieldValues[ 0 ];
  1424. break;
  1425. case 'zSpacing':
  1426. zSpacing = fieldValues[ 0 ];
  1427. break;
  1428. default:
  1429. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  1430. break;
  1431. }
  1432. }
  1433. // vertex data
  1434. const vertices = [];
  1435. const normals = [];
  1436. const colors = [];
  1437. const uvs = [];
  1438. for ( let i = 0; i < zDimension; i ++ ) {
  1439. for ( let j = 0; j < xDimension; j ++ ) {
  1440. // compute a row major index
  1441. const index = i * xDimension + j;
  1442. // vertices
  1443. const x = xSpacing * i;
  1444. const y = height[ index ];
  1445. const z = zSpacing * j;
  1446. vertices.push( x, y, z );
  1447. // colors
  1448. if ( color && colorPerVertex === true ) {
  1449. const r = color[ index * 3 + 0 ];
  1450. const g = color[ index * 3 + 1 ];
  1451. const b = color[ index * 3 + 2 ];
  1452. colors.push( r, g, b );
  1453. }
  1454. // normals
  1455. if ( normal && normalPerVertex === true ) {
  1456. const xn = normal[ index * 3 + 0 ];
  1457. const yn = normal[ index * 3 + 1 ];
  1458. const zn = normal[ index * 3 + 2 ];
  1459. normals.push( xn, yn, zn );
  1460. }
  1461. // uvs
  1462. if ( texCoord ) {
  1463. const s = texCoord[ index * 2 + 0 ];
  1464. const t = texCoord[ index * 2 + 1 ];
  1465. uvs.push( s, t );
  1466. } else {
  1467. uvs.push( i / ( xDimension - 1 ), j / ( zDimension - 1 ) );
  1468. }
  1469. }
  1470. }
  1471. // indices
  1472. const indices = [];
  1473. for ( let i = 0; i < xDimension - 1; i ++ ) {
  1474. for ( let j = 0; j < zDimension - 1; j ++ ) {
  1475. // from https://tecfa.unige.ch/guides/vrml/vrml97/spec/part1/nodesRef.html#ElevationGrid
  1476. const a = i + j * xDimension;
  1477. const b = i + ( j + 1 ) * xDimension;
  1478. const c = i + 1 + ( j + 1 ) * xDimension;
  1479. const d = i + 1 + j * xDimension;
  1480. // faces
  1481. if ( ccw === true ) {
  1482. indices.push( a, c, b );
  1483. indices.push( c, a, d );
  1484. } else {
  1485. indices.push( a, b, c );
  1486. indices.push( c, d, a );
  1487. }
  1488. }
  1489. }
  1490. //
  1491. const positionAttribute = toNonIndexedAttribute( indices, new THREE.Float32BufferAttribute( vertices, 3 ) );
  1492. const uvAttribute = toNonIndexedAttribute( indices, new THREE.Float32BufferAttribute( uvs, 2 ) );
  1493. let colorAttribute;
  1494. let normalAttribute;
  1495. // color attribute
  1496. if ( color ) {
  1497. if ( colorPerVertex === false ) {
  1498. for ( let i = 0; i < xDimension - 1; i ++ ) {
  1499. for ( let j = 0; j < zDimension - 1; j ++ ) {
  1500. const index = i + j * ( xDimension - 1 );
  1501. const r = color[ index * 3 + 0 ];
  1502. const g = color[ index * 3 + 1 ];
  1503. const b = color[ index * 3 + 2 ];
  1504. // one color per quad
  1505. colors.push( r, g, b );
  1506. colors.push( r, g, b );
  1507. colors.push( r, g, b );
  1508. colors.push( r, g, b );
  1509. colors.push( r, g, b );
  1510. colors.push( r, g, b );
  1511. }
  1512. }
  1513. colorAttribute = new THREE.Float32BufferAttribute( colors, 3 );
  1514. } else {
  1515. colorAttribute = toNonIndexedAttribute( indices, new THREE.Float32BufferAttribute( colors, 3 ) );
  1516. }
  1517. }
  1518. // normal attribute
  1519. if ( normal ) {
  1520. if ( normalPerVertex === false ) {
  1521. for ( let i = 0; i < xDimension - 1; i ++ ) {
  1522. for ( let j = 0; j < zDimension - 1; j ++ ) {
  1523. const index = i + j * ( xDimension - 1 );
  1524. const xn = normal[ index * 3 + 0 ];
  1525. const yn = normal[ index * 3 + 1 ];
  1526. const zn = normal[ index * 3 + 2 ];
  1527. // one normal per quad
  1528. normals.push( xn, yn, zn );
  1529. normals.push( xn, yn, zn );
  1530. normals.push( xn, yn, zn );
  1531. normals.push( xn, yn, zn );
  1532. normals.push( xn, yn, zn );
  1533. normals.push( xn, yn, zn );
  1534. }
  1535. }
  1536. normalAttribute = new THREE.Float32BufferAttribute( normals, 3 );
  1537. } else {
  1538. normalAttribute = toNonIndexedAttribute( indices, new THREE.Float32BufferAttribute( normals, 3 ) );
  1539. }
  1540. } else {
  1541. normalAttribute = computeNormalAttribute( indices, vertices, creaseAngle );
  1542. }
  1543. // build geometry
  1544. const geometry = new THREE.BufferGeometry();
  1545. geometry.setAttribute( 'position', positionAttribute );
  1546. geometry.setAttribute( 'normal', normalAttribute );
  1547. geometry.setAttribute( 'uv', uvAttribute );
  1548. if ( colorAttribute ) geometry.setAttribute( 'color', colorAttribute );
  1549. // "solid" influences the material so let's store it for later use
  1550. geometry._solid = solid;
  1551. geometry._type = 'mesh';
  1552. return geometry;
  1553. }
  1554. function buildExtrusionNode( node ) {
  1555. let crossSection = [ 1, 1, 1, - 1, - 1, - 1, - 1, 1, 1, 1 ];
  1556. let spine = [ 0, 0, 0, 0, 1, 0 ];
  1557. let scale;
  1558. let orientation;
  1559. let beginCap = true;
  1560. let ccw = true;
  1561. let creaseAngle = 0;
  1562. let endCap = true;
  1563. let solid = true;
  1564. const fields = node.fields;
  1565. for ( let i = 0, l = fields.length; i < l; i ++ ) {
  1566. const field = fields[ i ];
  1567. const fieldName = field.name;
  1568. const fieldValues = field.values;
  1569. switch ( fieldName ) {
  1570. case 'beginCap':
  1571. beginCap = fieldValues[ 0 ];
  1572. break;
  1573. case 'ccw':
  1574. ccw = fieldValues[ 0 ];
  1575. break;
  1576. case 'convex':
  1577. // field not supported
  1578. break;
  1579. case 'creaseAngle':
  1580. creaseAngle = fieldValues[ 0 ];
  1581. break;
  1582. case 'crossSection':
  1583. crossSection = fieldValues;
  1584. break;
  1585. case 'endCap':
  1586. endCap = fieldValues[ 0 ];
  1587. break;
  1588. case 'orientation':
  1589. orientation = fieldValues;
  1590. break;
  1591. case 'scale':
  1592. scale = fieldValues;
  1593. break;
  1594. case 'solid':
  1595. solid = fieldValues[ 0 ];
  1596. break;
  1597. case 'spine':
  1598. spine = fieldValues; // only extrusion along the Y-axis are supported so far
  1599. break;
  1600. default:
  1601. console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
  1602. break;
  1603. }
  1604. }
  1605. const crossSectionClosed = crossSection[ 0 ] === crossSection[ crossSection.length - 2 ] && crossSection[ 1 ] === crossSection[ crossSection.length - 1 ];
  1606. // vertices
  1607. const vertices = [];
  1608. const spineVector = new THREE.Vector3();
  1609. const scaling = new THREE.Vector3();
  1610. const axis = new THREE.Vector3();
  1611. const vertex = new THREE.Vector3();
  1612. const quaternion = new THREE.Quaternion();
  1613. for ( let i = 0, j = 0, o = 0, il = spine.length; i < il; i += 3, j += 2, o += 4 ) {
  1614. spineVector.fromArray( spine, i );
  1615. scaling.x = scale ? scale[ j + 0 ] : 1;
  1616. scaling.y = 1;
  1617. scaling.z = scale ? scale[ j + 1 ] : 1;
  1618. axis.x = orientation ? orientation[ o + 0 ] : 0;
  1619. axis.y = orientation ? orientation[ o + 1 ] : 0;
  1620. axis.z = orientation ? orientation[ o + 2 ] : 1;
  1621. const angle = orientation ? orientation[ o + 3 ] : 0;
  1622. for ( let k = 0, kl = crossSection.length; k < kl; k += 2 ) {
  1623. vertex.x = crossSection[ k + 0 ];
  1624. vertex.y = 0;
  1625. vertex.z = crossSection[ k + 1 ];
  1626. // scale
  1627. vertex.multiply( scaling );
  1628. // rotate
  1629. quaternion.setFromAxisAngle( axis, angle );
  1630. vertex.applyQuaternion( quaternion );
  1631. // translate
  1632. vertex.add( spineVector );
  1633. vertices.push( vertex.x, vertex.y, vertex.z );
  1634. }
  1635. }
  1636. // indices
  1637. const indices = [];
  1638. const spineCount = spine.length / 3;
  1639. const crossSectionCount = crossSection.length / 2;
  1640. for ( let i = 0; i < spineCount - 1; i ++ ) {
  1641. for ( let j = 0; j < crossSectionCount - 1; j ++ ) {
  1642. const a = j + i * crossSectionCount;
  1643. let b = j + 1 + i * crossSectionCount;
  1644. const c = j + ( i + 1 ) * crossSectionCount;
  1645. let d = j + 1 + ( i + 1 ) * crossSectionCount;
  1646. if ( j === crossSectionCount - 2 && crossSectionClosed === true ) {
  1647. b = i * crossSectionCount;
  1648. d = ( i + 1 ) * crossSectionCount;
  1649. }
  1650. if ( ccw === true ) {
  1651. indices.push( a, b, c );
  1652. indices.push( c, b, d );
  1653. } else {
  1654. indices.push( a, c, b );
  1655. indices.push( c, d, b );
  1656. }
  1657. }
  1658. }
  1659. // triangulate cap
  1660. if ( beginCap === true || endCap === true ) {
  1661. const contour = [];
  1662. for ( let i = 0, l = crossSection.length; i < l; i += 2 ) {
  1663. contour.push( new THREE.Vector2( crossSection[ i ], crossSection[ i + 1 ] ) );
  1664. }
  1665. const faces = THREE.ShapeUtils.triangulateShape( contour, [] );
  1666. const capIndices = [];
  1667. for ( let i = 0, l = faces.length; i < l; i ++ ) {
  1668. const face = faces[ i ];
  1669. capIndices.push( face[ 0 ], face[ 1 ], face[ 2 ] );
  1670. }
  1671. // begin cap
  1672. if ( beginCap === true ) {
  1673. for ( let i = 0, l = capIndices.length; i < l; i += 3 ) {
  1674. if ( ccw === true ) {
  1675. indices.push( capIndices[ i + 0 ], capIndices[ i + 1 ], capIndices[ i + 2 ] );
  1676. } else {
  1677. indices.push( capIndices[ i + 0 ], capIndices[ i + 2 ], capIndices[ i + 1 ] );
  1678. }
  1679. }
  1680. }
  1681. // end cap
  1682. if ( endCap === true ) {
  1683. const indexOffset = crossSectionCount * ( spineCount - 1 ); // references to the first vertex of the last cross section
  1684. for ( let i = 0, l = capIndices.length; i < l; i += 3 ) {
  1685. if ( ccw === true ) {
  1686. indices.push( indexOffset + capIndices[ i + 0 ], indexOffset + capIndices[ i + 2 ], indexOffset + capIndices[ i + 1 ] );
  1687. } else {
  1688. indices.push( indexOffset + capIndices[ i + 0 ], indexOffset + capIndices[ i + 1 ], indexOffset + capIndices[ i + 2 ] );
  1689. }
  1690. }
  1691. }
  1692. }
  1693. const positionAttribute = toNonIndexedAttribute( indices, new THREE.Float32BufferAttribute( vertices, 3 ) );
  1694. const normalAttribute = computeNormalAttribute( indices, vertices, creaseAngle );
  1695. const geometry = new THREE.BufferGeometry();
  1696. geometry.setAttribute( 'position', positionAttribute );
  1697. geometry.setAttribute( 'normal', normalAttribute );
  1698. // no uvs yet
  1699. // "solid" influences the material so let's store it for later use
  1700. geometry._solid = solid;
  1701. geometry._type = 'mesh';
  1702. return geometry;
  1703. }
  1704. // helper functions
  1705. function resolveUSE( identifier ) {
  1706. const node = nodeMap[ identifier ];
  1707. const build = getNode( node );
  1708. // because the same 3D objects can have different transformations, it's necessary to clone them.
  1709. // materials can be influenced by the geometry (e.g. vertex normals). cloning is necessary to avoid
  1710. // any side effects
  1711. return build.isObject3D || build.isMaterial ? build.clone() : build;
  1712. }
  1713. function parseFieldChildren( children, owner ) {
  1714. for ( let i = 0, l = children.length; i < l; i ++ ) {
  1715. const object = getNode( children[ i ] );
  1716. if ( object instanceof THREE.Object3D ) owner.add( object );
  1717. }
  1718. }
  1719. function triangulateFaceIndex( index, ccw ) {
  1720. const indices = [];
  1721. // since face defintions can have more than three vertices, it's necessary to
  1722. // perform a simple triangulation
  1723. let start = 0;
  1724. for ( let i = 0, l = index.length; i < l; i ++ ) {
  1725. const i1 = index[ start ];
  1726. const i2 = index[ i + ( ccw ? 1 : 2 ) ];
  1727. const i3 = index[ i + ( ccw ? 2 : 1 ) ];
  1728. indices.push( i1, i2, i3 );
  1729. // an index of -1 indicates that the current face has ended and the next one begins
  1730. if ( index[ i + 3 ] === - 1 || i + 3 >= l ) {
  1731. i += 3;
  1732. start = i + 1;
  1733. }
  1734. }
  1735. return indices;
  1736. }
  1737. function triangulateFaceData( data, index ) {
  1738. const triangulatedData = [];
  1739. let start = 0;
  1740. for ( let i = 0, l = index.length; i < l; i ++ ) {
  1741. const stride = start * 3;
  1742. const x = data[ stride ];
  1743. const y = data[ stride + 1 ];
  1744. const z = data[ stride + 2 ];
  1745. triangulatedData.push( x, y, z );
  1746. // an index of -1 indicates that the current face has ended and the next one begins
  1747. if ( index[ i + 3 ] === - 1 || i + 3 >= l ) {
  1748. i += 3;
  1749. start ++;
  1750. }
  1751. }
  1752. return triangulatedData;
  1753. }
  1754. function flattenData( data, index ) {
  1755. const flattenData = [];
  1756. for ( let i = 0, l = index.length; i < l; i ++ ) {
  1757. const i1 = index[ i ];
  1758. const stride = i1 * 3;
  1759. const x = data[ stride ];
  1760. const y = data[ stride + 1 ];
  1761. const z = data[ stride + 2 ];
  1762. flattenData.push( x, y, z );
  1763. }
  1764. return flattenData;
  1765. }
  1766. function expandLineIndex( index ) {
  1767. const indices = [];
  1768. for ( let i = 0, l = index.length; i < l; i ++ ) {
  1769. const i1 = index[ i ];
  1770. const i2 = index[ i + 1 ];
  1771. indices.push( i1, i2 );
  1772. // an index of -1 indicates that the current line has ended and the next one begins
  1773. if ( index[ i + 2 ] === - 1 || i + 2 >= l ) {
  1774. i += 2;
  1775. }
  1776. }
  1777. return indices;
  1778. }
  1779. function expandLineData( data, index ) {
  1780. const triangulatedData = [];
  1781. let start = 0;
  1782. for ( let i = 0, l = index.length; i < l; i ++ ) {
  1783. const stride = start * 3;
  1784. const x = data[ stride ];
  1785. const y = data[ stride + 1 ];
  1786. const z = data[ stride + 2 ];
  1787. triangulatedData.push( x, y, z );
  1788. // an index of -1 indicates that the current line has ended and the next one begins
  1789. if ( index[ i + 2 ] === - 1 || i + 2 >= l ) {
  1790. i += 2;
  1791. start ++;
  1792. }
  1793. }
  1794. return triangulatedData;
  1795. }
  1796. const vA = new THREE.Vector3();
  1797. const vB = new THREE.Vector3();
  1798. const vC = new THREE.Vector3();
  1799. const uvA = new THREE.Vector2();
  1800. const uvB = new THREE.Vector2();
  1801. const uvC = new THREE.Vector2();
  1802. function computeAttributeFromIndexedData( coordIndex, index, data, itemSize ) {
  1803. const array = [];
  1804. // we use the coordIndex.length as delimiter since normalIndex must contain at least as many indices
  1805. for ( let i = 0, l = coordIndex.length; i < l; i += 3 ) {
  1806. const a = index[ i ];
  1807. const b = index[ i + 1 ];
  1808. const c = index[ i + 2 ];
  1809. if ( itemSize === 2 ) {
  1810. uvA.fromArray( data, a * itemSize );
  1811. uvB.fromArray( data, b * itemSize );
  1812. uvC.fromArray( data, c * itemSize );
  1813. array.push( uvA.x, uvA.y );
  1814. array.push( uvB.x, uvB.y );
  1815. array.push( uvC.x, uvC.y );
  1816. } else {
  1817. vA.fromArray( data, a * itemSize );
  1818. vB.fromArray( data, b * itemSize );
  1819. vC.fromArray( data, c * itemSize );
  1820. array.push( vA.x, vA.y, vA.z );
  1821. array.push( vB.x, vB.y, vB.z );
  1822. array.push( vC.x, vC.y, vC.z );
  1823. }
  1824. }
  1825. return new THREE.Float32BufferAttribute( array, itemSize );
  1826. }
  1827. function computeAttributeFromFaceData( index, faceData ) {
  1828. const array = [];
  1829. for ( let i = 0, j = 0, l = index.length; i < l; i += 3, j ++ ) {
  1830. vA.fromArray( faceData, j * 3 );
  1831. array.push( vA.x, vA.y, vA.z );
  1832. array.push( vA.x, vA.y, vA.z );
  1833. array.push( vA.x, vA.y, vA.z );
  1834. }
  1835. return new THREE.Float32BufferAttribute( array, 3 );
  1836. }
  1837. function computeAttributeFromLineData( index, lineData ) {
  1838. const array = [];
  1839. for ( let i = 0, j = 0, l = index.length; i < l; i += 2, j ++ ) {
  1840. vA.fromArray( lineData, j * 3 );
  1841. array.push( vA.x, vA.y, vA.z );
  1842. array.push( vA.x, vA.y, vA.z );
  1843. }
  1844. return new THREE.Float32BufferAttribute( array, 3 );
  1845. }
  1846. function toNonIndexedAttribute( indices, attribute ) {
  1847. const array = attribute.array;
  1848. const itemSize = attribute.itemSize;
  1849. const array2 = new array.constructor( indices.length * itemSize );
  1850. let index = 0,
  1851. index2 = 0;
  1852. for ( let i = 0, l = indices.length; i < l; i ++ ) {
  1853. index = indices[ i ] * itemSize;
  1854. for ( let j = 0; j < itemSize; j ++ ) {
  1855. array2[ index2 ++ ] = array[ index ++ ];
  1856. }
  1857. }
  1858. return new THREE.Float32BufferAttribute( array2, itemSize );
  1859. }
  1860. const ab = new THREE.Vector3();
  1861. const cb = new THREE.Vector3();
  1862. function computeNormalAttribute( index, coord, creaseAngle ) {
  1863. const faces = [];
  1864. const vertexNormals = {};
  1865. // prepare face and raw vertex normals
  1866. for ( let i = 0, l = index.length; i < l; i += 3 ) {
  1867. const a = index[ i ];
  1868. const b = index[ i + 1 ];
  1869. const c = index[ i + 2 ];
  1870. const face = new Face( a, b, c );
  1871. vA.fromArray( coord, a * 3 );
  1872. vB.fromArray( coord, b * 3 );
  1873. vC.fromArray( coord, c * 3 );
  1874. cb.subVectors( vC, vB );
  1875. ab.subVectors( vA, vB );
  1876. cb.cross( ab );
  1877. cb.normalize();
  1878. face.normal.copy( cb );
  1879. if ( vertexNormals[ a ] === undefined ) vertexNormals[ a ] = [];
  1880. if ( vertexNormals[ b ] === undefined ) vertexNormals[ b ] = [];
  1881. if ( vertexNormals[ c ] === undefined ) vertexNormals[ c ] = [];
  1882. vertexNormals[ a ].push( face.normal );
  1883. vertexNormals[ b ].push( face.normal );
  1884. vertexNormals[ c ].push( face.normal );
  1885. faces.push( face );
  1886. }
  1887. // compute vertex normals and build final geometry
  1888. const normals = [];
  1889. for ( let i = 0, l = faces.length; i < l; i ++ ) {
  1890. const face = faces[ i ];
  1891. const nA = weightedNormal( vertexNormals[ face.a ], face.normal, creaseAngle );
  1892. const nB = weightedNormal( vertexNormals[ face.b ], face.normal, creaseAngle );
  1893. const nC = weightedNormal( vertexNormals[ face.c ], face.normal, creaseAngle );
  1894. vA.fromArray( coord, face.a * 3 );
  1895. vB.fromArray( coord, face.b * 3 );
  1896. vC.fromArray( coord, face.c * 3 );
  1897. normals.push( nA.x, nA.y, nA.z );
  1898. normals.push( nB.x, nB.y, nB.z );
  1899. normals.push( nC.x, nC.y, nC.z );
  1900. }
  1901. return new THREE.Float32BufferAttribute( normals, 3 );
  1902. }
  1903. function weightedNormal( normals, vector, creaseAngle ) {
  1904. const normal = new THREE.Vector3();
  1905. if ( creaseAngle === 0 ) {
  1906. normal.copy( vector );
  1907. } else {
  1908. for ( let i = 0, l = normals.length; i < l; i ++ ) {
  1909. if ( normals[ i ].angleTo( vector ) < creaseAngle ) {
  1910. normal.add( normals[ i ] );
  1911. }
  1912. }
  1913. }
  1914. return normal.normalize();
  1915. }
  1916. function toColorArray( colors ) {
  1917. const array = [];
  1918. for ( let i = 0, l = colors.length; i < l; i += 3 ) {
  1919. array.push( new THREE.Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) );
  1920. }
  1921. return array;
  1922. }
  1923. /**
  1924. * Vertically paints the faces interpolating between the
  1925. * specified colors at the specified angels. This is used for the Background
  1926. * node, but could be applied to other nodes with multiple faces as well.
  1927. *
  1928. * When used with the Background node, default is directionIsDown is true if
  1929. * interpolating the skyColor down from the Zenith. When interpolationg up from
  1930. * the Nadir i.e. interpolating the groundColor, the directionIsDown is false.
  1931. *
  1932. * The first angle is never specified, it is the Zenith (0 rad). Angles are specified
  1933. * in radians. The geometry is thought a sphere, but could be anything. The color interpolation
  1934. * is linear along the Y axis in any case.
  1935. *
  1936. * You must specify one more color than you have angles at the beginning of the colors array.
  1937. * This is the color of the Zenith (the top of the shape).
  1938. *
  1939. * @param {BufferGeometry} geometry
  1940. * @param {number} radius
  1941. * @param {array} angles
  1942. * @param {array} colors
  1943. * @param {boolean} topDown - Whether to work top down or bottom up.
  1944. */
  1945. function paintFaces( geometry, radius, angles, colors, topDown ) {
  1946. // compute threshold values
  1947. const thresholds = [];
  1948. const startAngle = topDown === true ? 0 : Math.PI;
  1949. for ( let i = 0, l = colors.length; i < l; i ++ ) {
  1950. let angle = i === 0 ? 0 : angles[ i - 1 ];
  1951. angle = topDown === true ? angle : startAngle - angle;
  1952. const point = new THREE.Vector3();
  1953. point.setFromSphericalCoords( radius, angle, 0 );
  1954. thresholds.push( point );
  1955. }
  1956. // generate vertex colors
  1957. const indices = geometry.index;
  1958. const positionAttribute = geometry.attributes.position;
  1959. const colorAttribute = new THREE.BufferAttribute( new Float32Array( geometry.attributes.position.count * 3 ), 3 );
  1960. const position = new THREE.Vector3();
  1961. const color = new THREE.Color();
  1962. for ( let i = 0; i < indices.count; i ++ ) {
  1963. const index = indices.getX( i );
  1964. position.fromBufferAttribute( positionAttribute, index );
  1965. let thresholdIndexA, thresholdIndexB;
  1966. let t = 1;
  1967. for ( let j = 1; j < thresholds.length; j ++ ) {
  1968. thresholdIndexA = j - 1;
  1969. thresholdIndexB = j;
  1970. const thresholdA = thresholds[ thresholdIndexA ];
  1971. const thresholdB = thresholds[ thresholdIndexB ];
  1972. if ( topDown === true ) {
  1973. // interpolation for sky color
  1974. if ( position.y <= thresholdA.y && position.y > thresholdB.y ) {
  1975. t = Math.abs( thresholdA.y - position.y ) / Math.abs( thresholdA.y - thresholdB.y );
  1976. break;
  1977. }
  1978. } else {
  1979. // interpolation for ground color
  1980. if ( position.y >= thresholdA.y && position.y < thresholdB.y ) {
  1981. t = Math.abs( thresholdA.y - position.y ) / Math.abs( thresholdA.y - thresholdB.y );
  1982. break;
  1983. }
  1984. }
  1985. }
  1986. const colorA = colors[ thresholdIndexA ];
  1987. const colorB = colors[ thresholdIndexB ];
  1988. color.copy( colorA ).lerp( colorB, t );
  1989. colorAttribute.setXYZ( index, color.r, color.g, color.b );
  1990. }
  1991. geometry.setAttribute( 'color', colorAttribute );
  1992. }
  1993. //
  1994. const textureLoader = new THREE.TextureLoader( this.manager );
  1995. textureLoader.setPath( this.resourcePath || path ).setCrossOrigin( this.crossOrigin );
  1996. // check version (only 2.0 is supported)
  1997. if ( data.indexOf( '#VRML V2.0' ) === - 1 ) {
  1998. throw Error( 'THREE.VRMLLexer: Version of VRML asset not supported.' );
  1999. }
  2000. // create JSON representing the tree structure of the VRML asset
  2001. const tree = generateVRMLTree( data );
  2002. // parse the tree structure to a three.js scene
  2003. const scene = parseTree( tree );
  2004. return scene;
  2005. }
  2006. }
  2007. class VRMLLexer {
  2008. constructor( tokens ) {
  2009. this.lexer = new chevrotain.Lexer( tokens ); // eslint-disable-line no-undef
  2010. }
  2011. lex( inputText ) {
  2012. const lexingResult = this.lexer.tokenize( inputText );
  2013. if ( lexingResult.errors.length > 0 ) {
  2014. console.error( lexingResult.errors );
  2015. throw Error( 'THREE.VRMLLexer: Lexing errors detected.' );
  2016. }
  2017. return lexingResult;
  2018. }
  2019. }
  2020. const CstParser = chevrotain.CstParser; // eslint-disable-line no-undef
  2021. class VRMLParser extends CstParser {
  2022. constructor( tokenVocabulary ) {
  2023. super( tokenVocabulary );
  2024. const $ = this;
  2025. const Version = tokenVocabulary[ 'Version' ];
  2026. const LCurly = tokenVocabulary[ 'LCurly' ];
  2027. const RCurly = tokenVocabulary[ 'RCurly' ];
  2028. const LSquare = tokenVocabulary[ 'LSquare' ];
  2029. const RSquare = tokenVocabulary[ 'RSquare' ];
  2030. const Identifier = tokenVocabulary[ 'Identifier' ];
  2031. const RouteIdentifier = tokenVocabulary[ 'RouteIdentifier' ];
  2032. const StringLiteral = tokenVocabulary[ 'StringLiteral' ];
  2033. const HexLiteral = tokenVocabulary[ 'HexLiteral' ];
  2034. const NumberLiteral = tokenVocabulary[ 'NumberLiteral' ];
  2035. const TrueLiteral = tokenVocabulary[ 'TrueLiteral' ];
  2036. const FalseLiteral = tokenVocabulary[ 'FalseLiteral' ];
  2037. const NullLiteral = tokenVocabulary[ 'NullLiteral' ];
  2038. const DEF = tokenVocabulary[ 'DEF' ];
  2039. const USE = tokenVocabulary[ 'USE' ];
  2040. const ROUTE = tokenVocabulary[ 'ROUTE' ];
  2041. const TO = tokenVocabulary[ 'TO' ];
  2042. const NodeName = tokenVocabulary[ 'NodeName' ];
  2043. $.RULE( 'vrml', function () {
  2044. $.SUBRULE( $.version );
  2045. $.AT_LEAST_ONE( function () {
  2046. $.SUBRULE( $.node );
  2047. } );
  2048. $.MANY( function () {
  2049. $.SUBRULE( $.route );
  2050. } );
  2051. } );
  2052. $.RULE( 'version', function () {
  2053. $.CONSUME( Version );
  2054. } );
  2055. $.RULE( 'node', function () {
  2056. $.OPTION( function () {
  2057. $.SUBRULE( $.def );
  2058. } );
  2059. $.CONSUME( NodeName );
  2060. $.CONSUME( LCurly );
  2061. $.MANY( function () {
  2062. $.SUBRULE( $.field );
  2063. } );
  2064. $.CONSUME( RCurly );
  2065. } );
  2066. $.RULE( 'field', function () {
  2067. $.CONSUME( Identifier );
  2068. $.OR2( [ {
  2069. ALT: function () {
  2070. $.SUBRULE( $.singleFieldValue );
  2071. }
  2072. }, {
  2073. ALT: function () {
  2074. $.SUBRULE( $.multiFieldValue );
  2075. }
  2076. } ] );
  2077. } );
  2078. $.RULE( 'def', function () {
  2079. $.CONSUME( DEF );
  2080. $.OR( [ {
  2081. ALT: function () {
  2082. $.CONSUME( Identifier );
  2083. }
  2084. }, {
  2085. ALT: function () {
  2086. $.CONSUME( NodeName );
  2087. }
  2088. } ] );
  2089. } );
  2090. $.RULE( 'use', function () {
  2091. $.CONSUME( USE );
  2092. $.OR( [ {
  2093. ALT: function () {
  2094. $.CONSUME( Identifier );
  2095. }
  2096. }, {
  2097. ALT: function () {
  2098. $.CONSUME( NodeName );
  2099. }
  2100. } ] );
  2101. } );
  2102. $.RULE( 'singleFieldValue', function () {
  2103. $.AT_LEAST_ONE( function () {
  2104. $.OR( [ {
  2105. ALT: function () {
  2106. $.SUBRULE( $.node );
  2107. }
  2108. }, {
  2109. ALT: function () {
  2110. $.SUBRULE( $.use );
  2111. }
  2112. }, {
  2113. ALT: function () {
  2114. $.CONSUME( StringLiteral );
  2115. }
  2116. }, {
  2117. ALT: function () {
  2118. $.CONSUME( HexLiteral );
  2119. }
  2120. }, {
  2121. ALT: function () {
  2122. $.CONSUME( NumberLiteral );
  2123. }
  2124. }, {
  2125. ALT: function () {
  2126. $.CONSUME( TrueLiteral );
  2127. }
  2128. }, {
  2129. ALT: function () {
  2130. $.CONSUME( FalseLiteral );
  2131. }
  2132. }, {
  2133. ALT: function () {
  2134. $.CONSUME( NullLiteral );
  2135. }
  2136. } ] );
  2137. } );
  2138. } );
  2139. $.RULE( 'multiFieldValue', function () {
  2140. $.CONSUME( LSquare );
  2141. $.MANY( function () {
  2142. $.OR( [ {
  2143. ALT: function () {
  2144. $.SUBRULE( $.node );
  2145. }
  2146. }, {
  2147. ALT: function () {
  2148. $.SUBRULE( $.use );
  2149. }
  2150. }, {
  2151. ALT: function () {
  2152. $.CONSUME( StringLiteral );
  2153. }
  2154. }, {
  2155. ALT: function () {
  2156. $.CONSUME( HexLiteral );
  2157. }
  2158. }, {
  2159. ALT: function () {
  2160. $.CONSUME( NumberLiteral );
  2161. }
  2162. }, {
  2163. ALT: function () {
  2164. $.CONSUME( NullLiteral );
  2165. }
  2166. } ] );
  2167. } );
  2168. $.CONSUME( RSquare );
  2169. } );
  2170. $.RULE( 'route', function () {
  2171. $.CONSUME( ROUTE );
  2172. $.CONSUME( RouteIdentifier );
  2173. $.CONSUME( TO );
  2174. $.CONSUME2( RouteIdentifier );
  2175. } );
  2176. this.performSelfAnalysis();
  2177. }
  2178. }
  2179. class Face {
  2180. constructor( a, b, c ) {
  2181. this.a = a;
  2182. this.b = b;
  2183. this.c = c;
  2184. this.normal = new THREE.Vector3();
  2185. }
  2186. }
  2187. const TEXTURE_TYPE = {
  2188. INTENSITY: 1,
  2189. INTENSITY_ALPHA: 2,
  2190. RGB: 3,
  2191. RGBA: 4
  2192. };
  2193. THREE.VRMLLoader = VRMLLoader;
  2194. } )();