diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 97626ba45445..bc437610c7f5 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -1,6 +1,7 @@ + \ No newline at end of file diff --git a/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_BaseColor.png b/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_BaseColor.png new file mode 100644 index 000000000000..b59459f8dc7c Binary files /dev/null and b/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_BaseColor.png differ diff --git a/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_Emissive.png b/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_Emissive.png new file mode 100644 index 000000000000..e48855d87d3a Binary files /dev/null and b/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_Emissive.png differ diff --git a/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_Normal.png b/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_Normal.png new file mode 100644 index 000000000000..d9ffe8f56034 Binary files /dev/null and b/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_Normal.png differ diff --git a/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_OcclusionRoughnessMetallic.png b/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_OcclusionRoughnessMetallic.png new file mode 100644 index 000000000000..d9ba0e7e9536 Binary files /dev/null and b/Apps/SampleData/models/GroundVehiclePBR/CougarBulbs_OcclusionRoughnessMetallic.png differ diff --git a/Apps/SampleData/models/GroundVehiclePBR/CougarOne_Normal.png b/Apps/SampleData/models/GroundVehiclePBR/CougarOne_Normal.png new file mode 100644 index 000000000000..795a3b4f9ab5 Binary files /dev/null and b/Apps/SampleData/models/GroundVehiclePBR/CougarOne_Normal.png differ diff --git a/Apps/SampleData/models/GroundVehiclePBR/CougarOne_OcclusionRoughnessMetallic.jpg b/Apps/SampleData/models/GroundVehiclePBR/CougarOne_OcclusionRoughnessMetallic.jpg new file mode 100644 index 000000000000..cf865fd0265d Binary files /dev/null and b/Apps/SampleData/models/GroundVehiclePBR/CougarOne_OcclusionRoughnessMetallic.jpg differ diff --git a/Apps/SampleData/models/GroundVehiclePBR/CougarOne_Rust_BaseColor.jpg b/Apps/SampleData/models/GroundVehiclePBR/CougarOne_Rust_BaseColor.jpg new file mode 100644 index 000000000000..97f618b38c99 Binary files /dev/null and b/Apps/SampleData/models/GroundVehiclePBR/CougarOne_Rust_BaseColor.jpg differ diff --git a/Apps/SampleData/models/GroundVehiclePBR/CougarTwo_Normal.png b/Apps/SampleData/models/GroundVehiclePBR/CougarTwo_Normal.png new file mode 100644 index 000000000000..7bb7a082a110 Binary files /dev/null and b/Apps/SampleData/models/GroundVehiclePBR/CougarTwo_Normal.png differ diff --git a/Apps/SampleData/models/GroundVehiclePBR/CougarTwo_OcclusionRoughnessMetallic.jpg b/Apps/SampleData/models/GroundVehiclePBR/CougarTwo_OcclusionRoughnessMetallic.jpg new file mode 100644 index 000000000000..dfb2629827c2 Binary files /dev/null and b/Apps/SampleData/models/GroundVehiclePBR/CougarTwo_OcclusionRoughnessMetallic.jpg differ diff --git a/Apps/SampleData/models/GroundVehiclePBR/CougarTwo_Rust_BaseColor.jpg b/Apps/SampleData/models/GroundVehiclePBR/CougarTwo_Rust_BaseColor.jpg new file mode 100644 index 000000000000..12780423d806 Binary files /dev/null and b/Apps/SampleData/models/GroundVehiclePBR/CougarTwo_Rust_BaseColor.jpg differ diff --git a/Apps/SampleData/models/GroundVehiclePBR/GroundVehicle.bin b/Apps/SampleData/models/GroundVehiclePBR/GroundVehicle.bin new file mode 100644 index 000000000000..597c04657c26 Binary files /dev/null and b/Apps/SampleData/models/GroundVehiclePBR/GroundVehicle.bin differ diff --git a/Apps/SampleData/models/GroundVehiclePBR/GroundVehiclePBR.gltf b/Apps/SampleData/models/GroundVehiclePBR/GroundVehiclePBR.gltf new file mode 100644 index 000000000000..c92e524c4b3c --- /dev/null +++ b/Apps/SampleData/models/GroundVehiclePBR/GroundVehiclePBR.gltf @@ -0,0 +1,484 @@ +{ + "accessors" : [ + { + "bufferView" : 0, + "componentType" : 5123, + "count" : 32538, + "max" : [ + 22876 + ], + "min" : [ + 11566 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 1, + "componentType" : 5126, + "count" : 22877, + "max" : [ + 3.6727895736694336, + 2.6324195861816406, + 1.3988499641418457 + ], + "min" : [ + -4.13224983215332, + 0.024001194164156914, + -1.3988499641418457 + ], + "type" : "VEC3" + }, + { + "bufferView" : 2, + "componentType" : 5126, + "count" : 22877, + "max" : [ + 1.0, + 1.0, + 1.0 + ], + "min" : [ + -1.0, + -1.0, + -1.0 + ], + "type" : "VEC3" + }, + { + "bufferView" : 3, + "componentType" : 5126, + "count" : 22877, + "max" : [ + 0.9899999499320984, + 0.9900000104680657 + ], + "min" : [ + 0.005954026710242033, + 0.008197009563446045 + ], + "type" : "VEC2" + }, + { + "bufferView" : 4, + "componentType" : 5123, + "count" : 1398, + "max" : [ + 22842 + ], + "min" : [ + 22476 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 5, + "componentType" : 5126, + "count" : 22877, + "max" : [ + 3.6727895736694336, + 2.6324195861816406, + 1.3988499641418457 + ], + "min" : [ + -4.13224983215332, + 0.024001194164156914, + -1.3988499641418457 + ], + "type" : "VEC3" + }, + { + "bufferView" : 6, + "componentType" : 5126, + "count" : 22877, + "max" : [ + 1.0, + 1.0, + 1.0 + ], + "min" : [ + -1.0, + -1.0, + -1.0 + ], + "type" : "VEC3" + }, + { + "bufferView" : 7, + "componentType" : 5126, + "count" : 22877, + "max" : [ + 0.9899999499320984, + 0.9900000104680657 + ], + "min" : [ + 0.005954026710242033, + 0.008197009563446045 + ], + "type" : "VEC2" + }, + { + "bufferView" : 8, + "componentType" : 5123, + "count" : 39396, + "max" : [ + 11565 + ], + "min" : [ + 0 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 9, + "componentType" : 5126, + "count" : 22877, + "max" : [ + 3.6727895736694336, + 2.6324195861816406, + 1.3988499641418457 + ], + "min" : [ + -4.13224983215332, + 0.024001194164156914, + -1.3988499641418457 + ], + "type" : "VEC3" + }, + { + "bufferView" : 10, + "componentType" : 5126, + "count" : 22877, + "max" : [ + 1.0, + 1.0, + 1.0 + ], + "min" : [ + -1.0, + -1.0, + -1.0 + ], + "type" : "VEC3" + }, + { + "bufferView" : 11, + "componentType" : 5126, + "count" : 22877, + "max" : [ + 0.9899999499320984, + 0.9900000104680657 + ], + "min" : [ + 0.005954026710242033, + 0.008197009563446045 + ], + "type" : "VEC2" + } + ], + "asset" : { + "generator" : "Khronos Blender glTF 2.0 exporter", + "version" : "2.0" + }, + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 65076, + "byteOffset" : 0, + "target" : 34963 + }, + { + "buffer" : 0, + "byteLength" : 274524, + "byteOffset" : 65076, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 274524, + "byteOffset" : 339600, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 183016, + "byteOffset" : 614124, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 2796, + "byteOffset" : 797140, + "target" : 34963 + }, + { + "buffer" : 0, + "byteLength" : 274524, + "byteOffset" : 799936, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 274524, + "byteOffset" : 1074460, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 183016, + "byteOffset" : 1348984, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 78792, + "byteOffset" : 1532000, + "target" : 34963 + }, + { + "buffer" : 0, + "byteLength" : 274524, + "byteOffset" : 1610792, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 274524, + "byteOffset" : 1885316, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 183016, + "byteOffset" : 2159840, + "target" : 34962 + } + ], + "buffers" : [ + { + "byteLength" : 2342856, + "uri" : "GroundVehicle.bin" + } + ], + "images" : [ + { + "uri" : "CougarBulbs_BaseColor.png" + }, + { + "uri" : "CougarBulbs_Normal.png" + }, + { + "uri" : "CougarBulbs_OcclusionRoughnessMetallic.png" + }, + { + "uri" : "CougarBulbs_Emissive.png" + }, + { + "uri" : "CougarOne_OcclusionRoughnessMetallic.jpg" + }, + { + "uri" : "CougarOne_Normal.png" + }, + { + "uri" : "CougarOne_Rust_BaseColor.jpg" + }, + { + "uri" : "CougarTwo_Rust_BaseColor.jpg" + }, + { + "uri" : "CougarTwo_Normal.png" + }, + { + "uri" : "CougarTwo_OcclusionRoughnessMetallic.jpg" + } + ], + "materials" : [ + { + "emissiveFactor" : [ + 1.0, + 1.0, + 1.0 + ], + "emissiveTexture" : { + "index" : 3 + }, + "name" : "CougarBulbs", + "normalTexture" : { + "index" : 1 + }, + "occlusionTexture" : { + "index" : 2 + }, + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicRoughnessTexture" : { + "index" : 2 + } + } + }, + { + "name" : "CougarOne", + "normalTexture" : { + "index" : 5 + }, + "occlusionTexture" : { + "index" : 4 + }, + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 6 + }, + "metallicRoughnessTexture" : { + "index" : 4 + } + } + }, + { + "name" : "CougarTwo", + "normalTexture" : { + "index" : 8 + }, + "occlusionTexture" : { + "index" : 9 + }, + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 7 + }, + "metallicRoughnessTexture" : { + "index" : 9 + } + } + } + ], + "meshes" : [ + { + "name" : "Default", + "primitives" : [ + { + "attributes" : { + "NORMAL" : 2, + "POSITION" : 1, + "TEXCOORD_0" : 3 + }, + "indices" : 0, + "material" : 1 + }, + { + "attributes" : { + "NORMAL" : 6, + "POSITION" : 5, + "TEXCOORD_0" : 7 + }, + "indices" : 4, + "material" : 0 + }, + { + "attributes" : { + "NORMAL" : 10, + "POSITION" : 9, + "TEXCOORD_0" : 11 + }, + "indices" : 8, + "material" : 2 + } + ] + } + ], + "nodes" : [ + { + "name" : "Camera", + "rotation" : [ + 0.483536034822464, + 0.33687159419059753, + -0.20870360732078552, + 0.7804827094078064 + ], + "translation" : [ + 4.353558540344238, + 3.4661054611206055, + 4.321204662322998 + ] + }, + { + "mesh" : 0, + "name" : "Default" + }, + { + "name" : "Lamp", + "rotation" : [ + 0.16907577216625214, + 0.7558803558349609, + -0.27217137813568115, + 0.5709474682807922 + ], + "scale" : [ + 1.0, + 1.0, + 0.9999998807907104 + ], + "translation" : [ + 4.076244831085205, + 5.903861999511719, + -1.0054539442062378 + ] + } + ], + "samplers" : [ + {} + ], + "scene" : 0, + "scenes" : [ + { + "name" : "Scene", + "nodes" : [ + 1, + 2, + 0 + ] + } + ], + "textures" : [ + { + "sampler" : 0, + "source" : 0 + }, + { + "sampler" : 0, + "source" : 1 + }, + { + "sampler" : 0, + "source" : 2 + }, + { + "sampler" : 0, + "source" : 3 + }, + { + "sampler" : 0, + "source" : 4 + }, + { + "sampler" : 0, + "source" : 5 + }, + { + "sampler" : 0, + "source" : 6 + }, + { + "sampler" : 0, + "source" : 7 + }, + { + "sampler" : 0, + "source" : 8 + }, + { + "sampler" : 0, + "source" : 9 + } + ] +} diff --git a/Apps/Sandcastle/gallery/Physically-Based Materials.html b/Apps/Sandcastle/gallery/Physically-Based Materials.html new file mode 100644 index 000000000000..29a10aecc059 --- /dev/null +++ b/Apps/Sandcastle/gallery/Physically-Based Materials.html @@ -0,0 +1,161 @@ + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+ + + diff --git a/Apps/Sandcastle/gallery/Physically-Based Materials.jpg b/Apps/Sandcastle/gallery/Physically-Based Materials.jpg new file mode 100644 index 000000000000..097a8dd90f1b Binary files /dev/null and b/Apps/Sandcastle/gallery/Physically-Based Materials.jpg differ diff --git a/Apps/Sandcastle/gallery/development/3D Models.html b/Apps/Sandcastle/gallery/development/3D Models.html index ffc969e4dc54..9739f74752ef 100644 --- a/Apps/Sandcastle/gallery/development/3D Models.html +++ b/Apps/Sandcastle/gallery/development/3D Models.html @@ -97,13 +97,13 @@ Cesium.knockout.getObservable(viewModel, 'color').subscribe( function(newValue) { - model.color = Cesium.Color.fromAlpha(getColor(newValue), viewModel.alpha); + model.color = Cesium.Color.fromAlpha(getColor(newValue), Number(viewModel.alpha)); } ); Cesium.knockout.getObservable(viewModel, 'alpha').subscribe( function(newValue) { - model.color = Cesium.Color.fromAlpha(getColor(viewModel.color), newValue); + model.color = Cesium.Color.fromAlpha(getColor(viewModel.color), Number(newValue)); } ); @@ -139,7 +139,7 @@ })); model.readyPromise.then(function(model) { - model.color = Cesium.Color.fromAlpha(getColor(viewModel.color), viewModel.alpha); + model.color = Cesium.Color.fromAlpha(getColor(viewModel.color), Number(viewModel.alpha)); model.colorBlendMode = getColorBlendMode(viewModel.colorBlendMode); model.colorBlendAmount = viewModel.colorBlendAmount; // Play and loop all animations at half-speed diff --git a/CHANGES.md b/CHANGES.md index 5e0e29d56022..dbd38248dd4a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -33,6 +33,7 @@ Change Log * Added `FrustumGeometry` and `FrustumOutlineGeometry`. [#5649](https://github.com/AnalyticalGraphicsInc/cesium/pull/5649) * Added an `options` parameter to the constructors of `PerspectiveFrustum`, `PerspectiveOffCenterFrustum`, `OrthographicFrustum`, and `OrthographicOffCenterFrustum` to set properties. [#5649](https://github.com/AnalyticalGraphicsInc/cesium/pull/5649) * Added `ClassificationPrimitive` which defines a volume and draws the intersection of the volume and terrain or 3D Tiles. [#5625](https://github.com/AnalyticalGraphicsInc/cesium/pull/5625) +* Added glTF 2.0 support, including physically-based material rendering, morph targets, and appropriate updating of glTF 1.0 models to 2.0. [#5641](https://github.com/AnalyticalGraphicsInc/cesium/pull/5641) * Fix for dynamic polylines with polyline dash material [#5681](https://github.com/AnalyticalGraphicsInc/cesium/pull/5681) ### 1.35.2 - 2017-07-11 diff --git a/LICENSE.md b/LICENSE.md index 3f9c51b5058f..61b0e64e78f5 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -306,7 +306,7 @@ https://github.com/kvz/phpjs > php.js is copyright 2013 Kevin van Zonneveld. > -> Portions copyright Brett Zamir (http://brett-zamir.me), Kevin van Zonneveld (http://kevin.vanzonneveld.net), Onno Marsman, Theriault, Michael White (http://getsprink.com), Waldo Malqui Silva, Paulo Freitas, Jack, Jonas Raoni Soares Silva (http://www.jsfromhell.com), Philip Peterson, Legaev Andrey, Ates Goral (http://magnetiq.com), Alex, Ratheous, Martijn Wieringa, Rafa? Kukawski (http://blog.kukawski.pl), lmeyrick (https://sourceforge.net/projects/bcmath-js/), Nate, Philippe Baumann, Enrique Gonzalez, Webtoolkit.info (http://www.webtoolkit.info/), Carlos R. L. Rodrigues (http://www.jsfromhell.com), Ash Searle (http://hexmen.com/blog/), Jani Hartikainen, travc, Ole Vrijenhoek, Erkekjetter, Michael Grier, Rafa? Kukawski (http://kukawski.pl), Johnny Mast (http://www.phpvrouwen.nl), T.Wild, d3x, http://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hex-in-javascript, Rafa? Kukawski (http://blog.kukawski.pl/), stag019, pilus, WebDevHobo (http://webdevhobo.blogspot.com/), marrtins, GeekFG (http://geekf blogspot.com), Andrea Giammarchi (http://webreflection.blogspot.com), Arpad Ray (mailto:arpad@php.net), gorthaur, Paul Smith, Tim de Koning (http://www.kingsquare.nl), Joris, Oleg Eremeev, Steve Hilder, majak, gettimeofday, KELAN, Josh Fraser (http://onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/), Marc Palau, Martin (http://www.erlenwiese.de/), Breaking Par Consulting Inc (http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256CFB006C45F7), Chris, Mirek Slugen, saulius, Alfonso Jimenez (http://www.alfonsojimenez.com), Diplom@t (http://difane.com/), felix, Mailfaker (http://www.weedem.fr/), Tyler Akins (http://rumkin.com), Caio Ariede (http://caioariede.com), Robin, Kankrelune (http://www.webfaktory.info/), Karol Kowalski, Imgen Tata (http://www.myipdf.com/), mdsjack (http://www.mdsjack.bo.it), Dreamer, Felix Geisendoerfer (http://www.debuggable.com/felix), Lars Fischer, AJ, David, Aman Gupta, Michael White, Public Domain (http://www.json.org/json2.js), Steven Levithan (http://b g.stevenlevithan.com), Sakimori, Pellentesque Malesuada, Thunder.m, Dj (http://phpjs.org/functions/htmlentities:425#comment_134018), Steve Clay, David James, Francois, class_exists, nobbler, T. Wild, Itsacon (http://www.itsacon.net/), date, Ole Vrijenhoek (http://www.nervous.nl/), Fox, Raphael (Ao RUDLER), Marco, noname, Mateusz "loonquawl" Zalega, Frank Forte, Arno, ger, mktime, john (http://www.jd-tech.net), Nick Kolosov (http://sammy.ru), marc andreu, Scott Cariss, Douglas Crockford (http://javascript.crockford.com), madipta, Slawomir Kaniecki, ReverseSyntax, Nathan, Alex Wilson, kenneth, Bayron Guevara, Adam Wallner (http://web2.bitbaro.hu/), paulo kuong, jmweb, Lincoln Ramsay, djmix, Pyerre, Jon Hohle, Thiago Mata (http://thiagomata.blog.com), lmeyrick (https://sourceforge.net/projects/bcmath-js/this.), Linuxworld, duncan, Gilbert, Sanjoy Roy, Shingo, sankai, Oskar Larsson H?gfeldt (http://oskar-lh.name/), Denny Wardhana, 0m3r, Everlasto, Subhasis Deb, josh, jd, Pier Paolo Ramon (http://www.mastersoup.c /), P, merabi, Soren Hansen, Eugene Bulkin (http://doubleaw.com/), Der Simon (http://innerdom.sourceforge.net/), echo is bad, Ozh, XoraX (http://www.xorax.info), EdorFaus, JB, J A R, Marc Jansen, Francesco, LH, Stoyan Kyosev (http://www.svest.org/), nord_ua, omid (http://phpjs.org/functions/380:380#comment_137122), Brad Touesnard, MeEtc (http://yass.meetcweb.com), Peter-Paul Koch (http://www.quirksmode.org/js/beat.html), Olivier Louvignes (http://mg-crea.com/), T0bsn, Tim Wiel, Bryan Elliott, Jalal Berrami, Martin, JT, David Randall, Thomas Beaucourt (http://www.webapp.fr), taith, vlado houba, Pierre-Luc Paour, Kristof Coomans (SCK-CEN Belgian Nucleair Research Centre), Martin Pool, Kirk Strobeck, Rick Waldron, Brant Messenger (http://www.brantmessenger.com/), Devan Penner-Woelk, Saulo Vallory, Wagner B. Soares, Artur Tchernychev, Valentina De Rosa, Jason Wong (http://carrot.org/), Christoph, Daniel Esteban, strftime, Mick@el, rezna, Simon Willison (http://simonwillison.net), Anton Ongson, Gabriel Paderni, M rco van Oort, penutbutterjelly, Philipp Lenssen, Bjorn Roesbeke (http://www.bjornroesbeke.be/), Bug?, Eric Nagel, Tomasz Wesolowski, Evertjan Garretsen, Bobby Drake, Blues (http://tech.bluesmoon.info/), Luke Godfrey, Pul, uestla, Alan C, Ulrich, Rafal Kukawski, Yves Sucaet, sowberry, Norman "zEh" Fuchs, hitwork, Zahlii, johnrembo, Nick Callen, Steven Levithan (stevenlevithan.com), ejsanders, Scott Baker, Brian Tafoya (http://www.premasolutions.com/), Philippe Jausions (http://pear.php.net/user/jausions), Aidan Lister (http://aidanlister.com/), Rob, e-mike, HKM, ChaosNo1, metjay, strcasecmp, strcmp, Taras Bogach, jpfle, Alexander Ermolaev (http://snippets.dzone.com/user/AlexanderErmolaev), DxGx, kilops, Orlando, dptr1988, Le Torbi, James (http://www.james-bell.co.uk/), Pedro Tainha (http://www.pedrotainha.com), James, Arnout Kazemier (http://www.3rd-Eden.com), Chris McMacken, gabriel paderni, Yannoo, FGFEmperor, baris ozdil, Tod Gentille, Greg Frazier, jakes, 3D-GRAF, Allan Jensen (http://www.winternet.no), Ho ard Yeend, Benjamin Lupton, davook, daniel airton wermann (http://wermann.com.br), Atli T¨®r, Maximusya, Ryan W Tenney (http://ryan.10e.us), Alexander M Beedie, fearphage (http://http/my.opera.com/fearphage/), Nathan Sepulveda, Victor, Matteo, Billy, stensi, Cord, Manish, T.J. Leahy, Riddler (http://www.frontierwebdev.com/), Rafa? Kukawski, FremyCompany, Matt Bradley, Tim de Koning, Luis Salazar (http://www.freaky-media.com/), Diogo Resende, Rival, Andrej Pavlovic, Garagoth, Le Torbi (http://www.letorbi.de/), Dino, Josep Sanz (http://www.ws3.es/), rem, Russell Walker (http://www.nbill.co.uk/), Jamie Beck (http://www.terabit.ca/), setcookie, Michael, YUI Library: http://developer.yahoo.com/yui/docs/YAHOO.util.DateLocale.html, Blues at http://hacks.bluesmoon.info/strftime/strftime.js, Ben (http://benblume.co.uk/), DtTvB (http://dt.in.th/2008-09-16.string-length-in-bytes.html), Andreas, William, meo, incidence, Cagri Ekin, Amirouche, Amir Habibi (http://www.residence-mixte.com/), Luke Smith (http://lucassmith.na ), Kheang Hok Chin (http://www.distantia.ca/), Jay Klehr, Lorenzo Pisani, Tony, Yen-Wei Liu, Greenseed, mk.keck, Leslie Hoare, dude, booeyOH, Ben Bryan +> Portions copyright Brett Zamir (http://brett-zamir.me), Kevin van Zonneveld (http://kevin.vanzonneveld.net), Onno Marsman, Theriault, Michael White (http://getsprink.com), Waldo Malqui Silva, Paulo Freitas, Jack, Jonas Raoni Soares Silva (http://www.jsfromhell.com), Philip Peterson, Legaev Andrey, Ates Goral (http://magnetiq.com), Alex, Ratheous, Martijn Wieringa, Rafa? Kukawski (http://blog.kukawski.pl), lmeyrick (https://sourceforge.net/projects/bcmath-js/), Nate, Philippe Baumann, Enrique Gonzalez, Webtoolkit.info (http://www.webtoolkit.info/), Carlos R. L. Rodrigues (http://www.jsfromhell.com), Ash Searle (http://hexmen.com/blog/), Jani Hartikainen, travc, Ole Vrijenhoek, Erkekjetter, Michael Grier, Rafa? Kukawski (http://kukawski.pl), Johnny Mast (http://www.phpvrouwen.nl), T.Wild, d3x, http://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hex-in-javascript, Rafa? Kukawski (http://blog.kukawski.pl/), stag019, pilus, WebDevHobo (http://webdevhobo.blogspot.com/), marrtins, GeekFG (http://geekf blogspot.com), Andrea Giammarchi (http://webreflection.blogspot.com), Arpad Ray (mailto:arpad@php.net), gorthaur, Paul Smith, Tim de Koning (http://www.kingsquare.nl), Joris, Oleg Eremeev, Steve Hilder, majak, gettimeofday, KELAN, Josh Fraser (http://onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/), Marc Palau, Martin (http://www.erlenwiese.de/), Breaking Par Consulting Inc (http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256CFB006C45F7), Chris, Mirek Slugen, saulius, Alfonso Jimenez (http://www.alfonsojimenez.com), Diplom@t (http://difane.com/), felix, Mailfaker (http://www.weedem.fr/), Tyler Akins (http://rumkin.com), Caio Ariede (http://caioariede.com), Robin, Kankrelune (http://www.webfaktory.info/), Karol Kowalski, Imgen Tata (http://www.myipdf.com/), mdsjack (http://www.mdsjack.bo.it), Dreamer, Felix Geisendoerfer (http://www.debuggable.com/felix), Lars Fischer, AJ, David, Aman Gupta, Michael White, Public Domain (http://www.json.org/json2.js), Steven Levithan (http://b g.stevenlevithan.com), Sakimori, Pellentesque Malesuada, Thunder.m, Dj (http://phpjs.org/functions/htmlentities:425#comment_134018), Steve Clay, David James, Francois, class_exists, nobbler, T. Wild, Itsacon (http://www.itsacon.net/), date, Ole Vrijenhoek (http://www.nervous.nl/), Fox, Raphael (Ao RUDLER), Marco, noname, Mateusz "loonquawl" Zalega, Frank Forte, Arno, ger, mktime, john (http://www.jd-tech.net), Nick Kolosov (http://sammy.ru), marc andreu, Scott Cariss, Douglas Crockford (http://javascript.crockford.com), madipta, Slawomir Kaniecki, ReverseSyntax, Nathan, Alex Wilson, kenneth, Bayron Guevara, Adam Wallner (http://web2.bitbaro.hu/), paulo kuong, jmweb, Lincoln Ramsay, djmix, Pyerre, Jon Hohle, Thiago Mata (http://thiagomata.blog.com), lmeyrick (https://sourceforge.net/projects/bcmath-js/this.), Linuxworld, duncan, Gilbert, Sanjoy Roy, Shingo, sankai, Oskar Larsson H?gfeldt (http://oskar-lh.name/), Denny Wardhana, 0m3r, Everlasto, Subhasis Deb, josh, jd, Pier Paolo Ramon (http://www.mastersoup.c /), P, merabi, Soren Hansen, Eugene Bulkin (http://doubleaw.com/), Der Simon (http://innerdom.sourceforge.net/), echo is bad, Ozh, XoraX (http://www.xorax.info), EdorFaus, JB, J A R, Marc Jansen, Francesco, LH, Stoyan Kyosev (http://www.svest.org/), nord_ua, omid (http://phpjs.org/functions/380:380#comment_137122), Brad Touesnard, MeEtc (http://yass.meetcweb.com), Peter-Paul Koch (http://www.quirksmode.org/js/beat.html), Olivier Louvignes (http://mg-crea.com/), T0bsn, Tim Wiel, Bryan Elliott, Jalal Berrami, Martin, JT, David Randall, Thomas Beaucourt (http://www.webapp.fr), taith, vlado houba, Pierre-Luc Paour, Kristof Coomans (SCK-CEN Belgian Nucleair Research Centre), Martin Pool, Kirk Strobeck, Rick Waldron, Brant Messenger (http://www.brantmessenger.com/), Devan Penner-Woelk, Saulo Vallory, Wagner B. Soares, Artur Tchernychev, Valentina De Rosa, Jason Wong (http://carrot.org/), Christoph, Daniel Esteban, strftime, Mick@el, rezna, Simon Willison (http://simonwillison.net), Anton Ongson, Gabriel Paderni, M rco van Oort, penutbutterjelly, Philipp Lenssen, Bjorn Roesbeke (http://www.bjornroesbeke.be/), Bug?, Eric Nagel, Tomasz Wesolowski, Evertjan Garretsen, Bobby Drake, Blues (http://tech.bluesmoon.info/), Luke Godfrey, Pul, uestla, Alan C, Ulrich, Rafal Kukawski, Yves Sucaet, sowberry, Norman "zEh" Fuchs, hitwork, Zahlii, johnrembo, Nick Callen, Steven Levithan (stevenlevithan.com), ejsanders, Scott Baker, Brian Tafoya (http://www.premasolutions.com/), Philippe Jausions (http://pear.php.net/user/jausions), Aidan Lister (http://aidanlister.com/), Rob, e-mike, HKM, ChaosNo1, metjay, strcasecmp, strcmp, Taras Bogach, jpfle, Alexander Ermolaev (http://snippets.dzone.com/user/AlexanderErmolaev), DxGx, kilops, Orlando, dptr1988, Le Torbi, James (http://www.james-bell.co.uk/), Pedro Tainha (http://www.pedrotainha.com), James, Arnout Kazemier (http://www.3rd-Eden.com), Chris McMacken, gabriel paderni, Yannoo, FGFEmperor, baris ozdil, Tod Gentille, Greg Frazier, jakes, 3D-GRAF, Allan Jensen (http://www.winternet.no), Ho ard Yeend, Benjamin Lupton, davook, daniel airton wermann (http://wermann.com.br), Atli T??r, Maximusya, Ryan W Tenney (http://ryan.10e.us), Alexander M Beedie, fearphage (http://http/my.opera.com/fearphage/), Nathan Sepulveda, Victor, Matteo, Billy, stensi, Cord, Manish, T.J. Leahy, Riddler (http://www.frontierwebdev.com/), Rafa? Kukawski, FremyCompany, Matt Bradley, Tim de Koning, Luis Salazar (http://www.freaky-media.com/), Diogo Resende, Rival, Andrej Pavlovic, Garagoth, Le Torbi (http://www.letorbi.de/), Dino, Josep Sanz (http://www.ws3.es/), rem, Russell Walker (http://www.nbill.co.uk/), Jamie Beck (http://www.terabit.ca/), setcookie, Michael, YUI Library: http://developer.yahoo.com/yui/docs/YAHOO.util.DateLocale.html, Blues at http://hacks.bluesmoon.info/strftime/strftime.js, Ben (http://benblume.co.uk/), DtTvB (http://dt.in.th/2008-09-16.string-length-in-bytes.html), Andreas, William, meo, incidence, Cagri Ekin, Amirouche, Amir Habibi (http://www.residence-mixte.com/), Luke Smith (http://lucassmith.na ), Kheang Hok Chin (http://www.distantia.ca/), Jay Klehr, Lorenzo Pisani, Tony, Yen-Wei Liu, Greenseed, mk.keck, Leslie Hoare, dude, booeyOH, Ben Bryan > > Licensed under the MIT (MIT-LICENSE.txt) license. > @@ -426,21 +426,21 @@ https://github.com/NVIDIAGameWorks/GraphicsSamples > > License: Subject to the terms of this Agreement, NVIDIA hereby grants to Developer a royalty-free, non-exclusive license to possess and to use the Materials. The following terms apply to the specified type of Material: > -> Source Code: Developer shall have the right to modify and create derivative works with the Source Code. Developer shall own any derivative works ("Derivatives") it creates to the Source Code, provided that Developer uses the Materials in accordance with the terms of this Agreement. Developer may distribute the Derivatives, provided that all NVIDIA copyright notices and trademarks are used properly and the Derivatives include the following statement: "This software contains source code provided by NVIDIA Corporation." +> Source Code: Developer shall have the right to modify and create derivative works with the Source Code. Developer shall own any derivative works ("Derivatives") it creates to the Source Code, provided that Developer uses the Materials in accordance with the terms of this Agreement. Developer may distribute the Derivatives, provided that all NVIDIA copyright notices and trademarks are used properly and the Derivatives include the following statement: "This software contains source code provided by NVIDIA Corporation." > > Object Code: Developer agrees not to disassemble, decompile or reverse engineer the Object Code versions of any of the Materials. Developer acknowledges that certain of the Materials provided in Object Code version may contain third party components that may be subject to restrictions, and expressly agrees not to attempt to modify or distribute such Materials without first receiving consent from NVIDIA. > -> Art Assets: Developer shall have the right to modify and create Derivatives of the Art Assets, but may not distribute any of the Art Assets or Derivatives created therefrom without NVIDIA’s prior written consent. +> Art Assets: Developer shall have the right to modify and create Derivatives of the Art Assets, but may not distribute any of the Art Assets or Derivatives created therefrom without NVIDIA's prior written consent. > -> Government End Users: If you are acquiring the Software on behalf of any unit or agency of the United States Government, the following provisions apply. The Government agrees the Software and documentation were developed at private expense and are provided with “RESTRICTED RIGHTS”. Use, duplication, or disclosure by the Government is subject to restrictions as set forth in DFARS 227.7202-1(a) and 227.7202-3(a) (1995), DFARS 252.227-7013(c)(1)(ii) (Oct 1988), FAR 12.212(a)(1995), FAR 52.227-19, (June 1987) or FAR 52.227-14(ALT III) (June 1987),as amended from time to time. In the event that this License, or any part thereof, is deemed inconsistent with the minimum rights identified in the Restricted Rights provisions, the minimum rights shall prevail. +> Government End Users: If you are acquiring the Software on behalf of any unit or agency of the United States Government, the following provisions apply. The Government agrees the Software and documentation were developed at private expense and are provided with "RESTRICTED RIGHTS". Use, duplication, or disclosure by the Government is subject to restrictions as set forth in DFARS 227.7202-1(a) and 227.7202-3(a) (1995), DFARS 252.227-7013(c)(1)(ii) (Oct 1988), FAR 12.212(a)(1995), FAR 52.227-19, (June 1987) or FAR 52.227-14(ALT III) (June 1987),as amended from time to time. In the event that this License, or any part thereof, is deemed inconsistent with the minimum rights identified in the Restricted Rights provisions, the minimum rights shall prevail. > No Other License. No rights or licenses are granted by NVIDIA under this License, expressly or by implication, with respect to any proprietary information or patent, copyright, trade secret or other intellectual property right owned or controlled by NVIDIA, except as expressly provided in this License. -> Term: This License is effective until terminated. NVIDIA may terminate this Agreement (and with it, all of Developer’s right to the Materials) immediately upon written notice (which may include email) to Developer, with or without cause. +> Term: This License is effective until terminated. NVIDIA may terminate this Agreement (and with it, all of Developer's right to the Materials) immediately upon written notice (which may include email) to Developer, with or without cause. > > Support: NVIDIA has no obligation to support or to continue providing or updating any of the Materials. > > No Warranty: THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA TO DEVELOPER HEREUNDER ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. > -> LIMITATION OF LIABILITY: NVIDIA SHALL NOT BE LIABLE TO DEVELOPER, DEVELOPER’S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY LIMITED REMEDY. IN NO EVENT SHALL NVIDIA’S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. +> LIMITATION OF LIABILITY: NVIDIA SHALL NOT BE LIABLE TO DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. ### NoSleep.js @@ -623,29 +623,54 @@ https://github.com/dcodeIO/ProtoBuf.js >Copyright (c) 2016, Daniel Wirtz All rights reserved. > >Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - +>modification, are permitted provided that the following conditions are +>met: +> >* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. +> notice, this list of conditions and the following disclaimer. >* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. +> notice, this list of conditions and the following disclaimer in the +> documentation and/or other materials provided with the distribution. >* Neither the name of its author, nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - +> may be used to endorse or promote products derived from this software +> without specific prior written permission. +> >THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +>"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +>LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +>A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +>OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +>SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +>LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +>DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +>THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +>(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +>OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +### gltf-WebGL-PBR + +https://github.com/KhronosGroup/glTF-WebGL-PBR + +>The MIT License +> +>Copyright (c) 2016-2017 Mohamad Moneimne and Contributors +> +>Permission is hereby granted, free of charge, to any person obtaining +>a copy of this software and associated documentation files (the "Software"), +>to deal in the Software without restriction, including without limitation the +>rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +>sell copies of the Software, and to permit persons to whom the Software is +>furnished to do so, subject to the following conditions: +> +>The above copyright notice and this permission notice shall be included in +>all copies or substantial portions of the Software. +> +>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +>INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +>PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +>HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +>CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +>OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Tests ===== diff --git a/Source/Core/CatmullRomSpline.js b/Source/Core/CatmullRomSpline.js index 8a4534b08396..fc417ce4a202 100644 --- a/Source/Core/CatmullRomSpline.js +++ b/Source/Core/CatmullRomSpline.js @@ -141,6 +141,7 @@ define([ * @see HermiteSpline * @see LinearSpline * @see QuaternionSpline + * @see WeightSpline */ function CatmullRomSpline(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); diff --git a/Source/Core/HermiteSpline.js b/Source/Core/HermiteSpline.js index 2d5e745dcc3b..e4d6209e8ca6 100644 --- a/Source/Core/HermiteSpline.js +++ b/Source/Core/HermiteSpline.js @@ -176,6 +176,7 @@ define([ * @see CatmullRomSpline * @see LinearSpline * @see QuaternionSpline + * @see WeightSpline */ function HermiteSpline(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); diff --git a/Source/Core/LinearSpline.js b/Source/Core/LinearSpline.js index e7bdd157527a..ad8b387727bc 100644 --- a/Source/Core/LinearSpline.js +++ b/Source/Core/LinearSpline.js @@ -47,6 +47,7 @@ define([ * @see HermiteSpline * @see CatmullRomSpline * @see QuaternionSpline + * @see WeightSpline */ function LinearSpline(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); diff --git a/Source/Core/QuaternionSpline.js b/Source/Core/QuaternionSpline.js index b39951a9779e..bfe4c792821c 100644 --- a/Source/Core/QuaternionSpline.js +++ b/Source/Core/QuaternionSpline.js @@ -89,6 +89,7 @@ define([ * @see HermiteSpline * @see CatmullRomSpline * @see LinearSpline + * @see WeightSpline */ function QuaternionSpline(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); diff --git a/Source/Core/WeightSpline.js b/Source/Core/WeightSpline.js new file mode 100644 index 000000000000..3ef4f9ce82cc --- /dev/null +++ b/Source/Core/WeightSpline.js @@ -0,0 +1,147 @@ +define([ + './Check', + './defaultValue', + './defined', + './defineProperties', + './DeveloperError', + './Spline' +], function( + Check, + defaultValue, + defined, + defineProperties, + DeveloperError, + Spline) { + 'use strict'; + + /** + * A spline that linearly interpolates over an array of weight values used by morph targets. + * + * @alias WeightSpline + * @constructor + * + * @param {Object} options Object with the following properties: + * @param {Number[]} options.times An array of strictly increasing, unit-less, floating-point times at each point. + * The values are in no way connected to the clock time. They are the parameterization for the curve. + * @param {Number[]} options.weights The array of floating-point control weights given. The weights are ordered such + * that all weights for the targets are given in chronological order and order in which they appear in + * the glTF from which the morph targets come. This means for 2 targets, weights = [w(0,0), w(0,1), w(1,0), w(1,1) ...] + * where i and j in w(i,j) are the time indices and target indices, respectively. + * + * @exception {DeveloperError} weights.length must be greater than or equal to 2. + * @exception {DeveloperError} times.length must be a factor of weights.length. + * + * + * @example + * var times = [ 0.0, 1.5, 3.0, 4.5, 6.0 ]; + * var weights = [0.0, 1.0, 0.25, 0.75, 0.5, 0.5, 0.75, 0.25, 1.0, 0.0]; //Two targets + * var spline = new Cesium.WeightSpline({ + * times : times, + * weights : weights + * }); + * + * var p0 = spline.evaluate(times[0]); + * + * @see LinearSpline + * @see HermiteSpline + * @see CatmullRomSpline + * @see QuaternionSpline + */ + function WeightSpline(options) { + options = defaultValue(options, defaultValue.EMPTY_OBJECT); + + var weights = options.weights; + var times = options.times; + + //>>includeStart('debug', pragmas.debug); + Check.defined('weights', weights); + Check.defined('times', times); + Check.typeOf.number.greaterThanOrEquals('weights.length', weights.length, 3); + if (weights.length % times.length !== 0) { + throw new DeveloperError('times.length must be a factor of weights.length.'); + } + //>>includeEnd('debug'); + + this._times = times; + this._weights = weights; + this._count = weights.length / times.length; + + this._lastTimeIndex = 0; + } + + defineProperties(WeightSpline.prototype, { + /** + * An array of times for the control weights. + * + * @memberof WeightSpline.prototype + * + * @type {Number[]} + * @readonly + */ + times : { + get : function() { + return this._times; + } + }, + + /** + * An array of floating-point array control weights. + * + * @memberof WeightSpline.prototype + * + * @type {Number[]} + * @readonly + */ + weights : { + get : function() { + return this._weights; + } + } + }); + + /** + * Finds an index i in times such that the parameter + * time is in the interval [times[i], times[i + 1]]. + * @function + * + * @param {Number} time The time. + * @returns {Number} The index for the element at the start of the interval. + * + * @exception {DeveloperError} time must be in the range [t0, tn], where t0 + * is the first element in the array times and tn is the last element + * in the array times. + */ + WeightSpline.prototype.findTimeInterval = Spline.prototype.findTimeInterval; + + /** + * Evaluates the curve at a given time. + * + * @param {Number} time The time at which to evaluate the curve. + * @param {Number[]} [result] The object onto which to store the result. + * @returns {Number[]} The modified result parameter or a new instance of the point on the curve at the given time. + * + * @exception {DeveloperError} time must be in the range [t0, tn], where t0 + * is the first element in the array times and tn is the last element + * in the array times. + */ + WeightSpline.prototype.evaluate = function(time, result) { + var weights = this.weights; + var times = this.times; + + var i = this._lastTimeIndex = this.findTimeInterval(time, this._lastTimeIndex); + var u = (time - times[i]) / (times[i + 1] - times[i]); + + if (!defined(result)) { + result = new Array(this._count); + } + + for (var j = 0; j < this._count; j++) { + var index = (i * this._count) + j; + result[j] = weights[index] * (1.0 - u) + weights[index + this._count] * u; + } + + return result; + }; + + return WeightSpline; +}); diff --git a/Source/Renderer/AutomaticUniforms.js b/Source/Renderer/AutomaticUniforms.js index 31b313ab7f60..89dafdc31d3e 100644 --- a/Source/Renderer/AutomaticUniforms.js +++ b/Source/Renderer/AutomaticUniforms.js @@ -1436,6 +1436,51 @@ define([ } }), + /** + * An automatic GLSL uniform containing the BRDF look up texture used for image-based lighting computations. + * + * @alias czm_brdfLut + * @glslUniform + * + * @example + * // GLSL declaration + * uniform sampler2D czm_brdfLut; + * + * // Example: For a given roughness and NdotV value, find the material's BRDF information in the red and green channels + * float roughness = 0.5; + * float NdotV = dot(normal, view); + * vec2 brdfLut = texture2D(czm_brdfLut, vec2(NdotV, 1.0 - roughness)).rg; + */ + czm_brdfLut : new AutomaticUniform({ + size : 1, + datatype : WebGLConstants.SAMPLER_2D, + getValue : function(uniformState) { + return uniformState.brdfLut; + } + }), + + /** + * An automatic GLSL uniform containing the environment map used within the scene. + * + * @alias czm_environmentMap + * @glslUniform + * + * @example + * // GLSL declaration + * uniform samplerCube czm_environmentMap; + * + * // Example: Create a perfect reflection of the environment map on a model + * float reflected = reflect(view, normal); + * vec4 reflectedColor = textureCube(czm_environmentMap, reflected); + */ + czm_environmentMap : new AutomaticUniform({ + size : 1, + datatype : WebGLConstants.SAMPLER_CUBE, + getValue : function(uniformState) { + return uniformState.environmentMap; + } + }), + /** * An automatic GLSL uniform representing a 3x3 rotation matrix that transforms * from True Equator Mean Equinox (TEME) axes to the pseudo-fixed axes at the current scene time. diff --git a/Source/Renderer/UniformState.js b/Source/Renderer/UniformState.js index 55af63a0fc0b..665b7317d7ea 100644 --- a/Source/Renderer/UniformState.js +++ b/Source/Renderer/UniformState.js @@ -1,10 +1,12 @@ define([ + './Sampler', '../Core/BoundingRectangle', '../Core/Cartesian2', '../Core/Cartesian3', '../Core/Cartesian4', '../Core/Cartographic', '../Core/Color', + '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', '../Core/EncodedCartesian3', @@ -16,12 +18,14 @@ define([ '../Core/Transforms', '../Scene/SceneMode' ], function( + Sampler, BoundingRectangle, Cartesian2, Cartesian3, Cartesian4, Cartographic, Color, + defaultValue, defined, defineProperties, EncodedCartesian3, @@ -150,6 +154,9 @@ define([ this._orthographicIn3D = false; this._backgroundColor = new Color(); + this._brdfLut = new Sampler(); + this._environmentMap = new Sampler(); + this._fogDensity = undefined; this._imagerySplitPosition = 0.0; @@ -796,6 +803,28 @@ define([ } }, + /** + * The look up texture used to find the BRDF for a material + * @memberof UniformState.prototype + * @type {Sampler} + */ + brdfLut : { + get : function() { + return this._brdfLut; + } + }, + + /** + * The environment map of the scene + * @memberof UniformState.prototype + * @type {Sampler} + */ + environmentMap : { + get : function() { + return this._environmentMap; + } + }, + /** * @memberof UniformState.prototype * @type {Number} @@ -975,6 +1004,12 @@ define([ setSunAndMoonDirections(this, frameState); + var brdfLutGenerator = frameState.brdfLutGenerator; + var brdfLut = defined(brdfLutGenerator) ? brdfLutGenerator.colorTexture : undefined; + this._brdfLut = brdfLut; + + this._environmentMap = defaultValue(frameState.environmentMap, frameState.context.defaultCubeMap); + this._fogDensity = frameState.fog.density; this._frameState = frameState; diff --git a/Source/Scene/Batched3DModel3DTileContent.js b/Source/Scene/Batched3DModel3DTileContent.js index 0bcd5f7e3181..7db1c61386cb 100644 --- a/Source/Scene/Batched3DModel3DTileContent.js +++ b/Source/Scene/Batched3DModel3DTileContent.js @@ -282,7 +282,7 @@ define([ batchTableBinaryByteLength = 0; featureTableJsonByteLength = 0; featureTableBinaryByteLength = 0; - deprecationWarning('b3dm-legacy-header', 'This b3dm header is using the legacy format [batchLength] [batchTableByteLength]. The new format is [featureTableJsonByteLength] [featureTableBinaryByteLength] [batchTableJsonByteLength] [batchTableBinaryByteLength] from https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Batched3DModel/README.md.'); + Batched3DModel3DTileContent._deprecationWarning('b3dm-legacy-header', 'This b3dm header is using the legacy format [batchLength] [batchTableByteLength]. The new format is [featureTableJsonByteLength] [featureTableBinaryByteLength] [batchTableJsonByteLength] [batchTableBinaryByteLength] from https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Batched3DModel/README.md.'); } else if (batchTableBinaryByteLength >= 570425344) { // Second legacy check byteOffset -= sizeOfUint32; @@ -291,7 +291,7 @@ define([ batchTableBinaryByteLength = featureTableBinaryByteLength; featureTableJsonByteLength = 0; featureTableBinaryByteLength = 0; - deprecationWarning('b3dm-legacy-header', 'This b3dm header is using the legacy format [batchTableJsonByteLength] [batchTableBinaryByteLength] [batchLength]. The new format is [featureTableJsonByteLength] [featureTableBinaryByteLength] [batchTableJsonByteLength] [batchTableBinaryByteLength] from https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Batched3DModel/README.md.'); + Batched3DModel3DTileContent._deprecationWarning('b3dm-legacy-header', 'This b3dm header is using the legacy format [batchTableJsonByteLength] [batchTableBinaryByteLength] [batchLength]. The new format is [featureTableJsonByteLength] [featureTableBinaryByteLength] [batchTableJsonByteLength] [batchTableBinaryByteLength] from https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Batched3DModel/README.md.'); } var featureTableJson; @@ -341,7 +341,15 @@ define([ if (gltfByteLength === 0) { throw new RuntimeError('glTF byte length must be greater than 0.'); } - var gltfView = new Uint8Array(arrayBuffer, byteOffset, gltfByteLength); + + var gltfView; + if (byteOffset % 4 === 0) { + gltfView = new Uint8Array(arrayBuffer, byteOffset, gltfByteLength); + } else { + // Create a copy of the glb so that it is 4-byte aligned + Batched3DModel3DTileContent._deprecationWarning('b3dm-glb-unaligned', 'The embedded glb is not aligned to a 4-byte boundary.'); + gltfView = new Uint8Array(uint8Array.subarray(byteOffset, byteOffset + gltfByteLength)); + } var pickObject = { content : content, diff --git a/Source/Scene/BrdfLutGenerator.js b/Source/Scene/BrdfLutGenerator.js new file mode 100644 index 000000000000..04ca2f7eb001 --- /dev/null +++ b/Source/Scene/BrdfLutGenerator.js @@ -0,0 +1,117 @@ +define([ + '../Core/BoundingRectangle', + '../Core/Color', + '../Core/defined', + '../Core/defineProperties', + '../Core/destroyObject', + '../Core/PixelFormat', + '../Renderer/Framebuffer', + '../Renderer/Pass', + '../Renderer/PixelDatatype', + '../Renderer/RenderState', + '../Renderer/Sampler', + '../Renderer/ShaderSource', + '../Renderer/Texture', + '../Renderer/TextureMagnificationFilter', + '../Renderer/TextureMinificationFilter', + '../Renderer/TextureWrap', + '../Shaders/BrdfLutGeneratorFS' + ], function( + BoundingRectangle, + Color, + defined, + defineProperties, + destroyObject, + PixelFormat, + Framebuffer, + Pass, + PixelDatatype, + RenderState, + Sampler, + ShaderSource, + Texture, + TextureMagnificationFilter, + TextureMinificationFilter, + TextureWrap, + BrdfLutGeneratorFS) { + 'use strict'; + + /** + * @private + */ + function BrdfLutGenerator() { + this._framebuffer = undefined; + this._colorTexture = undefined; + this._drawCommand = undefined; + } + + defineProperties(BrdfLutGenerator.prototype, { + colorTexture : { + get : function() { + return this._colorTexture; + } + } + }); + + function createCommand(generator, context) { + var framebuffer = generator._framebuffer; + + var drawCommand = context.createViewportQuadCommand(BrdfLutGeneratorFS, { + framebuffer : framebuffer, + renderState : RenderState.fromCache({ + viewport : new BoundingRectangle(0.0, 0.0, 256.0, 256.0) + }) + }); + + generator._drawCommand = drawCommand; + } + + function createFramebuffer(generator, context) { + var colorTexture = new Texture({ + context : context, + width : 256, + height: 256, + pixelFormat : PixelFormat.RGBA, + pixelDatatype : PixelDatatype.UNSIGNED_BYTE, + sampler : new Sampler({ + wrapS : TextureWrap.CLAMP_TO_EDGE, + wrapT : TextureWrap.CLAMP_TO_EDGE, + minificationFilter : TextureMinificationFilter.NEAREST, + magnificationFilter : TextureMagnificationFilter.NEAREST + }) + }); + + generator._colorTexture = colorTexture; + + var framebuffer = new Framebuffer({ + context : context, + colorTextures : [colorTexture], + destroyAttachments : false + }); + + generator._framebuffer = framebuffer; + } + + BrdfLutGenerator.prototype.update = function(frameState) { + if (!defined(this._colorTexture)) { + var context = frameState.context; + + createFramebuffer(this, context); + createCommand(this, context); + this._drawCommand.execute(context); + this._framebuffer = this._framebuffer && this._framebuffer.destroy(); + this._drawCommand.shaderProgram = this._drawCommand.shaderProgram && this._drawCommand.shaderProgram.destroy(); + } + }; + + BrdfLutGenerator.prototype.isDestroyed = function() { + return false; + }; + + BrdfLutGenerator.prototype.destroy = function() { + this._colorTexture = this._colorTexture && this._colorTexture.destroy(); + return destroyObject(this); + }; + + return BrdfLutGenerator; +}); diff --git a/Source/Scene/ClassificationPrimitive.js b/Source/Scene/ClassificationPrimitive.js index 86440fcecf86..ae0d0ef2f7fb 100644 --- a/Source/Scene/ClassificationPrimitive.js +++ b/Source/Scene/ClassificationPrimitive.js @@ -1,4 +1,3 @@ -/*global define*/ define([ '../Core/ColorGeometryInstanceAttribute', '../Core/defaultValue', diff --git a/Source/Scene/FrameState.js b/Source/Scene/FrameState.js index 2f3826452682..89e9d1343059 100644 --- a/Source/Scene/FrameState.js +++ b/Source/Scene/FrameState.js @@ -38,6 +38,18 @@ define([ */ this.shadowMaps = []; + /** + * The BRDF look up texture generator used for image-based lighting for PBR models + * @type {BrdfLutGenerator} + */ + this.brdfLutGenerator = undefined; + + /** + * The environment map used for image-based lighting for PBR models + * @type {CubeMap} + */ + this.environmentMap = undefined; + /** * The current mode of the scene. * diff --git a/Source/Scene/Instanced3DModel3DTileContent.js b/Source/Scene/Instanced3DModel3DTileContent.js index 429f51d35200..2bd40a0ae6db 100644 --- a/Source/Scene/Instanced3DModel3DTileContent.js +++ b/Source/Scene/Instanced3DModel3DTileContent.js @@ -6,6 +6,7 @@ define([ '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', + '../Core/deprecationWarning', '../Core/destroyObject', '../Core/DeveloperError', '../Core/Ellipsoid', @@ -34,6 +35,7 @@ define([ defaultValue, defined, defineProperties, + deprecationWarning, destroyObject, DeveloperError, Ellipsoid, @@ -91,6 +93,9 @@ define([ initialize(this, arrayBuffer, byteOffset); } + // This can be overridden for testing purposes + Instanced3DModel3DTileContent._deprecationWarning = deprecationWarning; + defineProperties(Instanced3DModel3DTileContent.prototype, { /** * @inheritdoc Cesium3DTileContent#featuresLength @@ -292,8 +297,15 @@ define([ if (gltfByteLength === 0) { throw new RuntimeError('glTF byte length is zero, i3dm must have a glTF to instance.'); } - var gltfView = new Uint8Array(arrayBuffer, byteOffset, gltfByteLength); - byteOffset += gltfByteLength; + + var gltfView; + if (byteOffset % 4 === 0) { + gltfView = new Uint8Array(arrayBuffer, byteOffset, gltfByteLength); + } else { + // Create a copy of the glb so that it is 4-byte aligned + Instanced3DModel3DTileContent._deprecationWarning('i3dm-glb-unaligned', 'The embedded glb is not aligned to a 4-byte boundary.'); + gltfView = new Uint8Array(uint8Array.subarray(byteOffset, byteOffset + gltfByteLength)); + } // Create model instance collection var collectionOptions = { diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index 0bd2a4d638bf..bb4ecb33b1ef 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -49,7 +49,16 @@ define([ '../Renderer/TextureMinificationFilter', '../Renderer/TextureWrap', '../Renderer/VertexArray', - '../ThirdParty/gltfDefaults', + '../ThirdParty/GltfPipeline/addDefaults', + '../ThirdParty/GltfPipeline/addPipelineExtras', + '../ThirdParty/GltfPipeline/ForEach', + '../ThirdParty/GltfPipeline/getAccessorByteStride', + '../ThirdParty/GltfPipeline/numberOfComponentsForType', + '../ThirdParty/GltfPipeline/parseBinaryGltf', + '../ThirdParty/GltfPipeline/processModelMaterialsCommon', + '../ThirdParty/GltfPipeline/processPbrMetallicRoughness', + '../ThirdParty/GltfPipeline/removePipelineExtras', + '../ThirdParty/GltfPipeline/updateVersion', '../ThirdParty/Uri', '../ThirdParty/when', './AttributeType', @@ -57,13 +66,11 @@ define([ './BlendingState', './ColorBlendMode', './getAttributeOrUniformBySemantic', - './getBinaryAccessor', './HeightReference', './JobType', './ModelAnimationCache', './ModelAnimationCollection', './ModelMaterial', - './modelMaterialsCommon', './ModelMesh', './ModelNode', './SceneMode', @@ -119,7 +126,16 @@ define([ TextureMinificationFilter, TextureWrap, VertexArray, - gltfDefaults, + addDefaults, + addPipelineExtras, + ForEach, + getAccessorByteStride, + numberOfComponentsForType, + parseBinaryGltf, + processModelMaterialsCommon, + processPbrMetallicRoughness, + removePipelineExtras, + updateVersion, Uri, when, AttributeType, @@ -127,13 +143,11 @@ define([ BlendingState, ColorBlendMode, getAttributeOrUniformBySemantic, - getBinaryAccessor, HeightReference, JobType, ModelAnimationCache, ModelAnimationCollection, ModelMaterial, - modelMaterialsCommon, ModelMesh, ModelNode, SceneMode, @@ -233,7 +247,6 @@ define([ function setCachedGltf(model, cachedGltf) { model._cachedGltf = cachedGltf; - model._animationIds = getAnimationIds(cachedGltf); } // glTF JSON can be big given embedded geometry, textures, and animations, so we @@ -243,10 +256,7 @@ define([ // Note that this is a global cache, compared to renderer resources, which // are cached per context. function CachedGltf(options) { - this._gltf = modelMaterialsCommon(gltfDefaults(options.gltf), { - addBatchIdToGeneratedShaders : options.addBatchIdToGeneratedShaders - }); - this._bgltf = options.bgltf; + this._gltf = options.gltf; this.ready = options.ready; this.modelsToLoad = []; this.count = 0; @@ -255,24 +265,17 @@ define([ defineProperties(CachedGltf.prototype, { gltf : { set : function(value) { - this._gltf = modelMaterialsCommon(gltfDefaults(value)); + this._gltf = value; }, get : function() { return this._gltf; } - }, - - bgltf : { - get : function() { - return this._bgltf; - } } }); - CachedGltf.prototype.makeReady = function(gltfJson, bgltf) { + CachedGltf.prototype.makeReady = function(gltfJson) { this.gltf = gltfJson; - this._bgltf = bgltf; var models = this.modelsToLoad; var length = models.length; @@ -288,8 +291,8 @@ define([ function getAnimationIds(cachedGltf) { var animationIds = []; - if (defined(cachedGltf) && defined(cachedGltf.gltf)) { - var animations = cachedGltf.gltf.animations; + if (defined(cachedGltf)) { + var animations = cachedGltf.animations; for (var id in animations) { if (animations.hasOwnProperty(id)) { animationIds.push(id); @@ -344,7 +347,6 @@ define([ * @param {Boolean} [options.debugWireframe=false] For debugging only. Draws the model in wireframe. * @param {HeightReference} [options.heightReference] Determines how the model is drawn relative to terrain. * @param {Scene} [options.scene] Must be passed in for models that use the height reference property. - * @param {Boolean} [options.addBatchIdToGeneratedShaders=false] Determines if shaders generated for materials using the KHR_materials_common extension should include a batchId attribute. For models contained in b3dm tiles. * @param {DistanceDisplayCondition} [options.distanceDisplayCondition] The condition specifying at what distance from the camera that this model will be displayed. * @param {Color} [options.color=Color.WHITE] A color that blends with the model's rendered color. * @param {ColorBlendMode} [options.colorBlendMode=ColorBlendMode.HIGHLIGHT] Defines how the color blends with the model. @@ -384,25 +386,17 @@ define([ if (gltf instanceof Uint8Array) { // Binary glTF - var result = parseBinaryGltfHeader(gltf); - - // KHR_binary_glTF is from the beginning of the binary section - if (result.binaryOffset !== 0) { - gltf = gltf.subarray(result.binaryOffset); - } + var parsedGltf = parseBinaryGltf(gltf); cachedGltf = new CachedGltf({ - gltf : result.glTF, - bgltf : gltf, - ready : true, - addBatchIdToGeneratedShaders : options.addBatchIdToGeneratedShaders + gltf : parsedGltf, + ready : true }); } else { // Normal glTF (JSON) cachedGltf = new CachedGltf({ gltf : options.gltf, - ready : true, - addBatchIdToGeneratedShaders : options.addBatchIdToGeneratedShaders + ready : true }); } @@ -627,6 +621,7 @@ define([ this._distanceDisplayCondition = options.distanceDisplayCondition; // Undocumented options + this._addBatchIdToGeneratedShaders = options.addBatchIdToGeneratedShaders; this._precreatedAttributes = options.precreatedAttributes; this._vertexShaderLoaded = options.vertexShaderLoaded; this._fragmentShaderLoaded = options.fragmentShaderLoaded; @@ -676,7 +671,8 @@ define([ }; this._uniformMaps = {}; // Not cached since it can be targeted by glTF animation - this._extensionsUsed = undefined; // Cached used extensions in a hash-map so we don't have to search the gltf array + this._extensionsUsed = undefined; // Cached used glTF extensions + this._extensionsRequired = undefined; // Cached required glTF extensions this._quantizedUniforms = {}; // Quantized uniforms for each program for WEB3D_quantized_attributes this._programPrimitives = {}; this._rendererResources = { // Cached between models with the same url/cache-key @@ -684,13 +680,14 @@ define([ vertexArrays : {}, programs : {}, pickPrograms : {}, - silhouettePrograms: {}, + silhouettePrograms : {}, textures : {}, samplers : {}, renderStates : {} }; this._cachedRendererResources = undefined; this._loadRendererResourcesFromCache = false; + this._updatedGltfVersion = false; this._cachedGeometryByteLength = 0; this._cachedTexturesByteLength = 0; @@ -983,6 +980,24 @@ define([ } }, + extensionsUsed : { + get : function() { + if (!defined(this._extensionsUsed)) { + this._extensionsUsed = getUsedExtensions(this); + } + return this._extensionsUsed; + } + }, + + extensionsRequired : { + get : function() { + if (!defined(this._extensionsRequired)) { + this._extensionsRequired = getRequiredExtensions(this); + } + return this._extensionsRequired; + } + }, + /** * Gets the model's up-axis. * By default models are y-up according to the glTF spec, however geo-referenced models will typically be z-up. @@ -1057,8 +1072,6 @@ define([ } }); - var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT; - function silhouetteSupported(context) { return context.stencilBuffer; } @@ -1086,41 +1099,6 @@ define([ return magic === 'glTF'; } - function parseBinaryGltfHeader(uint8Array) { - //>>includeStart('debug', pragmas.debug); - if (!containsGltfMagic(uint8Array)) { - throw new DeveloperError('bgltf is not a valid Binary glTF file.'); - } - //>>includeEnd('debug'); - - var view = new DataView(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteLength); - var byteOffset = 0; - - byteOffset += sizeOfUint32; // Skip magic number - - //>>includeStart('debug', pragmas.debug); - var version = view.getUint32(byteOffset, true); - if (version !== 1) { - throw new DeveloperError('Only Binary glTF version 1 is supported. Version ' + version + ' is not.'); - } - //>>includeEnd('debug'); - byteOffset += sizeOfUint32; - - byteOffset += sizeOfUint32; // Skip length - - var sceneLength = view.getUint32(byteOffset, true); - byteOffset += sizeOfUint32 + sizeOfUint32; // Skip sceneFormat - - var sceneOffset = byteOffset; - var binOffset = sceneOffset + sceneLength; - - var json = getStringFromTypedArray(uint8Array, sceneOffset, sceneLength); - return { - glTF: JSON.parse(json), - binaryOffset: binOffset - }; - } - /** *

* Creates a model from a glTF asset. When the model is ready to render, i.e., when the external binary, image, @@ -1227,12 +1205,9 @@ define([ var array = new Uint8Array(arrayBuffer); if (containsGltfMagic(array)) { // Load binary glTF - var result = parseBinaryGltfHeader(array); + var parsedGltf = parseBinaryGltf(array); // KHR_binary_glTF is from the beginning of the binary section - if (result.binaryOffset !== 0) { - array = array.subarray(result.binaryOffset); - } - cachedGltf.makeReady(result.glTF, array); + cachedGltf.makeReady(parsedGltf, array); } else { // Load text (JSON) glTF var json = getStringFromTypedArray(array); @@ -1337,7 +1312,8 @@ define([ }; } - function computeBoundingSphere(model, gltf) { + function computeBoundingSphere(model) { + var gltf = model.gltf; var gltfNodes = gltf.nodes; var gltfMeshes = gltf.meshes; var rootNodes = gltf.scenes[gltf.scene].nodes; @@ -1357,24 +1333,22 @@ define([ n = nodeStack.pop(); var transformToRoot = n._transformToRoot; - var meshes = n.meshes; - if (defined(meshes)) { - var meshesLength = meshes.length; - for (var j = 0; j < meshesLength; ++j) { - var primitives = gltfMeshes[meshes[j]].primitives; - var primitivesLength = primitives.length; - for (var m = 0; m < primitivesLength; ++m) { - var positionAccessor = primitives[m].attributes.POSITION; - if (defined(positionAccessor)) { - var minMax = getAccessorMinMax(gltf, positionAccessor); - var aMin = Cartesian3.fromArray(minMax.min, 0, aMinScratch); - var aMax = Cartesian3.fromArray(minMax.max, 0, aMaxScratch); - if (defined(min) && defined(max)) { - Matrix4.multiplyByPoint(transformToRoot, aMin, aMin); - Matrix4.multiplyByPoint(transformToRoot, aMax, aMax); - Cartesian3.minimumByComponent(min, aMin, min); - Cartesian3.maximumByComponent(max, aMax, max); - } + var meshId = n.mesh; + if (defined(meshId)) { + var mesh = gltfMeshes[meshId]; + var primitives = mesh.primitives; + var primitivesLength = primitives.length; + for (var m = 0; m < primitivesLength; ++m) { + var positionAccessor = primitives[m].attributes.POSITION; + if (defined(positionAccessor)) { + var minMax = getAccessorMinMax(gltf, positionAccessor); + var aMin = Cartesian3.fromArray(minMax.min, 0, aMinScratch); + var aMax = Cartesian3.fromArray(minMax.max, 0, aMaxScratch); + if (defined(min) && defined(max)) { + Matrix4.multiplyByPoint(transformToRoot, aMin, aMin); + Matrix4.multiplyByPoint(transformToRoot, aMax, aMax); + Cartesian3.minimumByComponent(min, aMin, min); + Cartesian3.maximumByComponent(max, aMax, max); } } } @@ -1410,31 +1384,37 @@ define([ }; } + function addBuffersToLoadResources(model) { + var gltf = model.gltf; + var loadResources = model._loadResources; + ForEach.buffer(gltf, function(buffer, id) { + loadResources.buffers[id] = buffer.extras._pipeline.source; + }); + } + function bufferLoad(model, id) { return function(arrayBuffer) { var loadResources = model._loadResources; - loadResources.buffers[id] = new Uint8Array(arrayBuffer); + var buffer = new Uint8Array(arrayBuffer); --loadResources.pendingBufferLoads; + model.gltf.buffers[id].extras._pipeline.source = buffer; }; } function parseBuffers(model) { + var loadResources = model._loadResources; + // Iterate this way for compatibility with objects and arrays var buffers = model.gltf.buffers; for (var id in buffers) { if (buffers.hasOwnProperty(id)) { var buffer = buffers[id]; - - // The extension 'KHR_binary_glTF' uses a special buffer entitled just 'binary_glTF'. - // The 'KHR_binary_glTF' check is for backwards compatibility for the Cesium model converter - // circa Cesium 1.15-1.20 when the converter incorrectly used the buffer name 'KHR_binary_glTF'. - if ((id === 'binary_glTF') || (id === 'KHR_binary_glTF')) { - // Buffer is the binary glTF file itself that is already loaded - var loadResources = model._loadResources; - loadResources.buffers[id] = model._cachedGltf.bgltf; - } - else if (buffer.type === 'arraybuffer') { - ++model._loadResources.pendingBufferLoads; + buffer.extras = defaultValue(buffer.extras, {}); + buffer.extras._pipeline = defaultValue(buffer.extras._pipeline, {}); + if (defined(buffer.extras._pipeline.source)) { + loadResources.buffers[id] = buffer.extras._pipeline.source; + } else { var bufferPath = joinUrls(model._baseUri, buffer.uri); + ++loadResources.pendingBufferLoads; loadArrayBuffer(bufferPath).then(bufferLoad(model, id)).otherwise(getFailedLoadFunction(model, 'buffer', bufferPath)); } } @@ -1443,18 +1423,15 @@ define([ function parseBufferViews(model) { var bufferViews = model.gltf.bufferViews; - var id; var vertexBuffersToCreate = model._loadResources.vertexBuffersToCreate; // Only ARRAY_BUFFER here. ELEMENT_ARRAY_BUFFER created below. - for (id in bufferViews) { - if (bufferViews.hasOwnProperty(id)) { - if (bufferViews[id].target === WebGLConstants.ARRAY_BUFFER) { - vertexBuffersToCreate.enqueue(id); - } + ForEach.bufferView(model.gltf, function(bufferView, id) { + if (bufferView.target === WebGLConstants.ARRAY_BUFFER) { + vertexBuffersToCreate.enqueue(id); } - } + }); var indexBuffersToCreate = model._loadResources.indexBuffersToCreate; var indexBufferIds = {}; @@ -1462,25 +1439,18 @@ define([ // The Cesium Renderer requires knowing the datatype for an index buffer // at creation type, which is not part of the glTF bufferview so loop // through glTF accessors to create the bufferview's index buffer. - var accessors = model.gltf.accessors; - for (id in accessors) { - if (accessors.hasOwnProperty(id)) { - var accessor = accessors[id]; - var bufferViewId = accessor.bufferView; - var bufferView = bufferViews[bufferViewId]; - - if ((bufferView.target === WebGLConstants.ELEMENT_ARRAY_BUFFER) && !defined(indexBufferIds[bufferViewId])) { - indexBufferIds[bufferViewId] = true; - indexBuffersToCreate.enqueue({ - id : bufferViewId, - // In theory, several glTF accessors with different componentTypes could - // point to the same glTF bufferView, which would break this. - // In practice, it is unlikely as it will be UNSIGNED_SHORT. - componentType : accessor.componentType - }); - } + ForEach.accessor(model.gltf, function(accessor) { + var bufferViewId = accessor.bufferView; + var bufferView = bufferViews[bufferViewId]; + + if ((bufferView.target === WebGLConstants.ELEMENT_ARRAY_BUFFER) && !defined(indexBufferIds[bufferViewId])) { + indexBufferIds[bufferViewId] = true; + indexBuffersToCreate.enqueue({ + id : bufferViewId, + componentType : accessor.componentType + }); } - } + }); } function shaderLoad(model, type, id) { @@ -1492,58 +1462,60 @@ define([ bufferView : undefined }; --loadResources.pendingShaderLoads; + model.gltf.shaders[id].extras._pipeline.source = source; }; } function parseShaders(model) { - var shaders = model.gltf.shaders; - for (var id in shaders) { - if (shaders.hasOwnProperty(id)) { - var shader = shaders[id]; - - // Shader references either uri (external or base64-encoded) or bufferView - if (defined(shader.extras) && defined(shader.extras.source)) { - model._loadResources.shaders[id] = { - source : shader.extras.source, - bufferView : undefined - }; - } - else if (defined(shader.extensions) && defined(shader.extensions.KHR_binary_glTF)) { - var binary = shader.extensions.KHR_binary_glTF; - model._loadResources.shaders[id] = { - source : undefined, - bufferView : binary.bufferView - }; - } else { - ++model._loadResources.pendingShaderLoads; - var shaderPath = joinUrls(model._baseUri, shader.uri); - loadText(shaderPath).then(shaderLoad(model, shader.type, id)).otherwise(getFailedLoadFunction(model, 'shader', shaderPath)); - } + var gltf = model.gltf; + var buffers = gltf.buffers; + var bufferViews = gltf.bufferViews; + ForEach.shader(gltf, function(shader, id) { + // Shader references either uri (external or base64-encoded) or bufferView + if (defined(shader.bufferView)) { + var bufferViewId = shader.bufferView; + var bufferView = bufferViews[bufferViewId]; + var bufferId = bufferView.buffer; + var buffer = buffers[bufferId]; + var source = getStringFromTypedArray(buffer.extras._pipeline.source, bufferView.byteOffset, bufferView.byteLength); + model._loadResources.shaders[id] = { + source : source, + bufferView : undefined + }; + shader.extras._pipeline.source = source; + } else if (defined(shader.extras._pipeline.source)) { + model._loadResources.shaders[id] = { + source : shader.extras._pipeline.source, + bufferView : undefined + }; + } else { + ++model._loadResources.pendingShaderLoads; + var shaderPath = joinUrls(model._baseUri, shader.uri); + loadText(shaderPath).then(shaderLoad(model, shader.type, id)).otherwise(getFailedLoadFunction(model, 'shader', shaderPath)); } - } + }); } function parsePrograms(model) { - var programs = model.gltf.programs; - for (var id in programs) { - if (programs.hasOwnProperty(id)) { - model._loadResources.programsToCreate.enqueue(id); - } - } + ForEach.program(model.gltf, function(program, id) { + model._loadResources.programsToCreate.enqueue(id); + }); } - function imageLoad(model, id) { + function imageLoad(model, textureId, imageId) { return function(image) { + var gltf = model.gltf; var loadResources = model._loadResources; --loadResources.pendingTextureLoads; loadResources.texturesToCreate.enqueue({ - id : id, + id : textureId, image : image, bufferView : image.bufferView, width : image.width, height : image.height, internalFormat : image.internalFormat }); + gltf.images[imageId].extras._pipeline.source = image; }; } @@ -1551,85 +1523,75 @@ define([ var crnRegex = /(^data:image\/crn)|(\.crn$)/i; function parseTextures(model, context) { - var images = model.gltf.images; - var textures = model.gltf.textures; - var binary; + var gltf = model.gltf; + var images = gltf.images; var uri; - for (var id in textures) { - if (textures.hasOwnProperty(id)) { - var gltfImage = images[textures[id].source]; - var extras = gltfImage.extras; - - binary = undefined; - uri = undefined; - - // First check for a compressed texture - if (defined(extras) && defined(extras.compressedImage3DTiles)) { - var crunch = extras.compressedImage3DTiles.crunch; - var s3tc = extras.compressedImage3DTiles.s3tc; - var pvrtc = extras.compressedImage3DTiles.pvrtc1; - var etc1 = extras.compressedImage3DTiles.etc1; - - if (context.s3tc && defined(crunch)) { - if (defined(crunch.extensions)&& defined(crunch.extensions.KHR_binary_glTF)) { - binary = crunch.extensions.KHR_binary_glTF; - } else { - uri = crunch.uri; - } - } else if (context.s3tc && defined(s3tc)) { - if (defined(s3tc.extensions)&& defined(s3tc.extensions.KHR_binary_glTF)) { - binary = s3tc.extensions.KHR_binary_glTF; - } else { - uri = s3tc.uri; - } - } else if (context.pvrtc && defined(pvrtc)) { - if (defined(pvrtc.extensions)&& defined(pvrtc.extensions.KHR_binary_glTF)) { - binary = pvrtc.extensions.KHR_binary_glTF; - } else { - uri = pvrtc.uri; - } - } else if (context.etc1 && defined(etc1)) { - if (defined(etc1.extensions)&& defined(etc1.extensions.KHR_binary_glTF)) { - binary = etc1.extensions.KHR_binary_glTF; - } else { - uri = etc1.uri; - } + ForEach.texture(gltf, function(texture, id) { + var imageId = texture.source; + var gltfImage = images[imageId]; + var extras = gltfImage.extras; + + var bufferViewId = gltfImage.bufferView; + uri = gltfImage.uri; + + // First check for a compressed texture + if (defined(extras) && defined(extras.compressedImage3DTiles)) { + var crunch = extras.compressedImage3DTiles.crunch; + var s3tc = extras.compressedImage3DTiles.s3tc; + var pvrtc = extras.compressedImage3DTiles.pvrtc1; + var etc1 = extras.compressedImage3DTiles.etc1; + + if (context.s3tc && defined(crunch)) { + if (defined(crunch.bufferView)) { + bufferViewId = crunch.bufferView; + } else { + uri = crunch.uri; } - } - - // No compressed texture, so image references either uri (external or base64-encoded) or bufferView - if (!defined(binary) && !defined(uri)) { - if (defined(gltfImage.extensions) && defined(gltfImage.extensions.KHR_binary_glTF)) { - binary = gltfImage.extensions.KHR_binary_glTF; + } else if (context.s3tc && defined(s3tc)) { + if (defined(s3tc.bufferView)) { + bufferViewId = s3tc.bufferView; } else { - uri = new Uri(gltfImage.uri); + uri = s3tc.uri; + } + } else if (context.pvrtc && defined(pvrtc)) { + if (defined(pvrtc.bufferView)) { + bufferViewId = pvrtc.bufferView; + } else { + uri = pvrtc.uri; + } + } else if (context.etc1 && defined(etc1)) { + if (defined(etc1.bufferView)) { + bufferViewId = etc1.bufferView; + } else { + uri = etc1.uri; } } + } - // Image references either uri (external or base64-encoded) or bufferView - if (defined(binary)) { - model._loadResources.texturesToCreateFromBufferView.enqueue({ - id : id, - image : undefined, - bufferView : binary.bufferView, - mimeType : binary.mimeType - }); + // Image references either uri (external or base64-encoded) or bufferView + if (defined(bufferViewId)) { + model._loadResources.texturesToCreateFromBufferView.enqueue({ + id : id, + image : undefined, + bufferView : bufferViewId, + mimeType : gltfImage.mimeType + }); + } else { + ++model._loadResources.pendingTextureLoads; + uri = new Uri(uri); + var imagePath = joinUrls(model._baseUri, uri); + + var promise; + if (ktxRegex.test(imagePath)) { + promise = loadKTX(imagePath); + } else if (crnRegex.test(imagePath)) { + promise = loadCRN(imagePath); } else { - ++model._loadResources.pendingTextureLoads; - var imagePath = joinUrls(model._baseUri, uri); - - var promise; - if (ktxRegex.test(imagePath)) { - promise = loadKTX(imagePath); - } else if (crnRegex.test(imagePath)) { - promise = loadCRN(imagePath); - } else { - promise = loadImage(imagePath); - } - promise.then(imageLoad(model, id)).otherwise(getFailedLoadFunction(model, 'image', imagePath)); + promise = loadImage(imagePath); } + promise.then(imageLoad(model, id, imageId)).otherwise(getFailedLoadFunction(model, 'image', imagePath)); } - } + }); } var nodeTranslationScratch = new Cartesian3(); @@ -1644,7 +1606,7 @@ define([ return Matrix4.fromTranslationQuaternionRotationScale( Cartesian3.fromArray(node.translation, 0, nodeTranslationScratch), Quaternion.unpack(node.rotation, 0, nodeQuaternionScratch), - Cartesian3.fromArray(node.scale, 0 , nodeScaleScratch)); + Cartesian3.fromArray(node.scale, 0, nodeScaleScratch)); } function parseNodes(model) { @@ -1653,57 +1615,54 @@ define([ var skinnedNodes = []; var skinnedNodesIds = model._loadResources.skinnedNodesIds; - var nodes = model.gltf.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; + ForEach.node(model.gltf, function(node, id) { + var runtimeNode = { + // Animation targets + matrix : undefined, + translation : undefined, + rotation : undefined, + scale : undefined, - var runtimeNode = { - // Animation targets - matrix : undefined, - translation : undefined, - rotation : undefined, - scale : undefined, + // Per-node show inherited from parent + computedShow : true, - // Per-node show inherited from parent - computedShow : true, + // Computed transforms + transformToRoot : new Matrix4(), + computedMatrix : new Matrix4(), + dirtyNumber : 0, // The frame this node was made dirty by an animation; for graph traversal - // Computed transforms - transformToRoot : new Matrix4(), - computedMatrix : new Matrix4(), - dirtyNumber : 0, // The frame this node was made dirty by an animation; for graph traversal + // Rendering + commands : [], // empty for transform, light, and camera nodes - // Rendering - commands : [], // empty for transform, light, and camera nodes + // Skinned node + inverseBindMatrices : undefined, // undefined when node is not skinned + bindShapeMatrix : undefined, // undefined when node is not skinned or identity + joints : [], // empty when node is not skinned + computedJointMatrices : [], // empty when node is not skinned - // Skinned node - inverseBindMatrices : undefined, // undefined when node is not skinned - bindShapeMatrix : undefined, // undefined when node is not skinned or identity - joints : [], // empty when node is not skinned - computedJointMatrices : [], // empty when node is not skinned + // Joint node + jointName : node.jointName, // undefined when node is not a joint - // Joint node - jointName : node.jointName, // undefined when node is not a joint + weights : [], - // Graph pointers - children : [], // empty for leaf nodes - parents : [], // empty for root nodes + // Graph pointers + children : [], // empty for leaf nodes + parents : [], // empty for root nodes - // Publicly-accessible ModelNode instance to modify animation targets - publicNode : undefined - }; - runtimeNode.publicNode = new ModelNode(model, node, runtimeNode, id, getTransform(node)); + // Publicly-accessible ModelNode instance to modify animation targets + publicNode : undefined + }; + runtimeNode.publicNode = new ModelNode(model, node, runtimeNode, id, getTransform(node)); - runtimeNodes[id] = runtimeNode; - runtimeNodesByName[node.name] = runtimeNode; + runtimeNodes[id] = runtimeNode; + runtimeNodesByName[node.name] = runtimeNode; - if (defined(node.skin)) { - skinnedNodesIds.push(id); - skinnedNodes.push(runtimeNode); - } + if (defined(node.skin)) { + skinnedNodesIds.push(id); + skinnedNodes.push(runtimeNode); } - } + }); model._runtime.nodes = runtimeNodes; model._runtime.nodesByName = runtimeNodesByName; @@ -1713,24 +1672,21 @@ define([ function parseMaterials(model) { var runtimeMaterialsByName = {}; var runtimeMaterialsById = {}; - var materials = model.gltf.materials; var uniformMaps = model._uniformMaps; - for (var id in materials) { - if (materials.hasOwnProperty(id)) { - // Allocated now so ModelMaterial can keep a reference to it. - uniformMaps[id] = { - uniformMap : undefined, - values : undefined, - jointMatrixUniformName : undefined - }; + ForEach.material(model.gltf, function(material, id) { + // Allocated now so ModelMaterial can keep a reference to it. + uniformMaps[id] = { + uniformMap : undefined, + values : undefined, + jointMatrixUniformName : undefined, + morphWeightsUniformName : undefined + }; - var material = materials[id]; - var modelMaterial = new ModelMaterial(model, material, id); - runtimeMaterialsByName[material.name] = modelMaterial; - runtimeMaterialsById[id] = modelMaterial; - } - } + var modelMaterial = new ModelMaterial(model, material, id); + runtimeMaterialsByName[material.name] = modelMaterial; + runtimeMaterialsById[id] = modelMaterial; + }); model._runtime.materialsByName = runtimeMaterialsByName; model._runtime.materialsById = runtimeMaterialsById; @@ -1739,58 +1695,56 @@ define([ function parseMeshes(model) { var runtimeMeshesByName = {}; var runtimeMaterialsById = model._runtime.materialsById; - var meshes = model.gltf.meshes; - var usesQuantizedAttributes = usesExtension(model, 'WEB3D_quantized_attributes'); - - for (var id in meshes) { - if (meshes.hasOwnProperty(id)) { - var mesh = meshes[id]; - runtimeMeshesByName[mesh.name] = new ModelMesh(mesh, runtimeMaterialsById, id); - if (usesQuantizedAttributes) { - // Cache primitives according to their program - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var i = 0; i < primitivesLength; i++) { - var primitive = primitives[i]; - var programId = getProgramForPrimitive(model, primitive); - var programPrimitives = model._programPrimitives[programId]; - if (!defined(programPrimitives)) { - programPrimitives = []; - model._programPrimitives[programId] = programPrimitives; - } - programPrimitives.push(primitive); + + ForEach.mesh(model.gltf, function(mesh, id) { + runtimeMeshesByName[mesh.name] = new ModelMesh(mesh, runtimeMaterialsById, id); + if (defined(model.extensionsUsed.WEB3D_quantized_attributes)) { + // Cache primitives according to their program + var primitives = mesh.primitives; + var primitivesLength = primitives.length; + for (var i = 0; i < primitivesLength; i++) { + var primitive = primitives[i]; + var programId = getProgramForPrimitive(model, primitive); + var programPrimitives = model._programPrimitives[programId]; + if (!defined(programPrimitives)) { + programPrimitives = []; + model._programPrimitives[programId] = programPrimitives; } + programPrimitives.push(primitive); } } - } + }); model._runtime.meshesByName = runtimeMeshesByName; } - function parse(model, context) { - if (!model._loadRendererResourcesFromCache) { - parseBuffers(model); - parseBufferViews(model); - parseShaders(model); - parsePrograms(model); - parseTextures(model, context); + function getUsedExtensions(model) { + var extensionsUsed = model.gltf.extensionsUsed; + var cachedExtensionsUsed = {}; + + if (defined(extensionsUsed)) { + var extensionsUsedLength = extensionsUsed.length; + for (var i = 0; i < extensionsUsedLength; i++) { + var extension = extensionsUsed[i]; + cachedExtensionsUsed[extension] = true; + } } - parseMaterials(model); - parseMeshes(model); - parseNodes(model); + return cachedExtensionsUsed; } - function usesExtension(model, extension) { - var cachedExtensionsUsed = model._extensionsUsed; - if (!defined(cachedExtensionsUsed)) { - var extensionsUsed = model.gltf.extensionsUsed; - cachedExtensionsUsed = {}; - var extensionsLength = extensionsUsed.length; - for (var i = 0; i < extensionsLength; i++) { - cachedExtensionsUsed[extensionsUsed[i]] = true; + function getRequiredExtensions(model) { + var extensionsRequired = model.gltf.extensionsRequired; + var cachedExtensionsRequired = {}; + + if (defined(extensionsRequired)) { + var extensionsRequiredLength = extensionsRequired.length; + for (var i = 0; i < extensionsRequiredLength; i++) { + var extension = extensionsRequired[i]; + cachedExtensionsRequired[extension] = true; } } - return defined(cachedExtensionsUsed[extension]); + + return cachedExtensionsRequired; } /////////////////////////////////////////////////////////////////////////// @@ -1935,18 +1889,6 @@ define([ return attributeLocations; } - function getShaderSource(model, shader) { - if (defined(shader.source)) { - return shader.source; - } - - var loadResources = model._loadResources; - var gltf = model.gltf; - var bufferView = gltf.bufferViews[shader.bufferView]; - - return getStringFromTypedArray(loadResources.getBuffer(bufferView)); - } - function replaceAllButFirstInString(string, find, replace) { var index = string.indexOf(find); return string.replace(new RegExp(find, 'g'), function(match, offset, all) { @@ -2008,14 +1950,19 @@ define([ if (getProgramForPrimitive(model, primitive) === programName) { for (var attributeSemantic in primitive.attributes) { if (primitive.attributes.hasOwnProperty(attributeSemantic)) { + var attributeVarName = getAttributeVariableName(model, primitive, attributeSemantic); + var accessorId = primitive.attributes[attributeSemantic]; + + if (attributeSemantic.charAt(0) === '_') { + attributeSemantic = attributeSemantic.substring(1); + } var decodeUniformVarName = 'gltf_u_dec_' + attributeSemantic.toLowerCase(); + var decodeUniformVarNameScale = decodeUniformVarName + '_scale'; var decodeUniformVarNameTranslate = decodeUniformVarName + '_translate'; if (!defined(quantizedUniforms[decodeUniformVarName]) && !defined(quantizedUniforms[decodeUniformVarNameScale])) { - var accessorId = primitive.attributes[attributeSemantic]; var quantizedAttributes = getQuantizedAttributes(model, accessorId); if (defined(quantizedAttributes)) { - var attributeVarName = getAttributeVariableName(model, primitive, attributeSemantic); var decodeMatrix = quantizedAttributes.decodeMatrix; var newMain = 'gltf_decoded_' + attributeSemantic; var decodedAttributeVarName = attributeVarName.replace('a_', 'gltf_a_dec_'); @@ -2135,12 +2082,12 @@ define([ function createProgram(id, model, context) { var programs = model.gltf.programs; - var shaders = model._loadResources.shaders; + var shaders = model.gltf.shaders; var program = programs[id]; var attributeLocations = createAttributeLocations(model, program.attributes); - var vs = getShaderSource(model, shaders[program.vertexShader]); - var fs = getShaderSource(model, shaders[program.fragmentShader]); + var vs = shaders[program.vertexShader].extras._pipeline.source; + var fs = shaders[program.fragmentShader].extras._pipeline.source; // Add pre-created attributes to attributeLocations var attributesLength = program.attributes.length; @@ -2153,7 +2100,7 @@ define([ } } - if (usesExtension(model, 'WEB3D_quantized_attributes')) { + if (model.extensionsUsed.WEB3D_quantized_attributes) { vs = modifyShaderForQuantizedAttributes(vs, id, model, context); } @@ -2313,6 +2260,10 @@ define([ var rendererSamplers = model._rendererResources.samplers; var sampler = rendererSamplers[texture.sampler]; + sampler = defaultValue(sampler, new Sampler({ + wrapS : TextureWrap.REPEAT, + wrapT : TextureWrap.REPEAT + })); var internalFormat = gltfTexture.internalFormat; @@ -2323,10 +2274,10 @@ define([ (sampler.minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST) || (sampler.minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR)); var requiresNpot = mipmap || - (sampler.wrapS === TextureWrap.REPEAT) || - (sampler.wrapS === TextureWrap.MIRRORED_REPEAT) || - (sampler.wrapT === TextureWrap.REPEAT) || - (sampler.wrapT === TextureWrap.MIRRORED_REPEAT); + (sampler.wrapS === TextureWrap.REPEAT) || + (sampler.wrapS === TextureWrap.MIRRORED_REPEAT) || + (sampler.wrapT === TextureWrap.REPEAT) || + (sampler.wrapT === TextureWrap.MIRRORED_REPEAT); var tx; var source = gltfTexture.image; @@ -2416,7 +2367,7 @@ define([ var programAttributeLocations = program._attributeLocations; // Note: WebGL shader compiler may have optimized and removed some attributes from programVertexAttributes - for (location in programVertexAttributes){ + for (location in programVertexAttributes) { if (programVertexAttributes.hasOwnProperty(location)) { var attribute = attributes[location]; index = programVertexAttributes[location].index; @@ -2445,8 +2396,9 @@ define([ return attributeLocations; } - function searchForest(forest, jointName, nodes) { + function mapJointNames(forest, nodes) { var length = forest.length; + var jointNodes = {}; for (var i = 0; i < length; ++i) { var stack = [forest[i]]; // Push root node of tree @@ -2454,8 +2406,8 @@ define([ var id = stack.pop(); var n = nodes[id]; - if (n.jointName === jointName) { - return id; + if (defined(n)) { + jointNodes[id] = id; } var children = n.children; @@ -2465,9 +2417,7 @@ define([ } } } - - // This should never happen; the skeleton should have a node for all joints in the skin. - return undefined; + return jointNodes; } function createJoints(model, runtimeSkins) { @@ -2491,17 +2441,18 @@ define([ // 2. These nodes form the root nodes of the forest to search for each joint in skin.jointNames. This search uses jointName, not the node's name. // 3. Search for the joint name among the gltf node hierarchy instead of the runtime node hierarchy. Child links aren't set up yet for runtime nodes. var forest = []; - var gltfSkeletons = node.skeletons; - var skeletonsLength = gltfSkeletons.length; - for (var k = 0; k < skeletonsLength; ++k) { - forest.push(gltfSkeletons[k]); + var skin = skins[node.skin]; + if (defined(skin.skeleton)) { + forest.push(skin.skeleton); } - var gltfJointNames = skins[node.skin].jointNames; + var mappedJointNames = mapJointNames(forest, nodes); + var gltfJointNames = skins[node.skin].joints; var jointNamesLength = gltfJointNames.length; for (var i = 0; i < jointNamesLength; ++i) { var jointName = gltfJointNames[i]; - var jointNode = runtimeNodes[searchForest(forest, jointName, nodes)]; + var nodeId = mappedJointNames[jointName]; + var jointNode = runtimeNodes[nodeId]; skinnedNode.joints.push(jointNode); } } @@ -2521,25 +2472,21 @@ define([ var gltf = model.gltf; var accessors = gltf.accessors; - var skins = gltf.skins; var runtimeSkins = {}; - for (var id in skins) { - if (skins.hasOwnProperty(id)) { - var skin = skins[id]; - var accessor = accessors[skin.inverseBindMatrices]; + ForEach.skin(gltf, function(skin, id) { + var accessor = accessors[skin.inverseBindMatrices]; - var bindShapeMatrix; - if (!Matrix4.equals(skin.bindShapeMatrix, Matrix4.IDENTITY)) { - bindShapeMatrix = Matrix4.clone(skin.bindShapeMatrix); - } - - runtimeSkins[id] = { - inverseBindMatrices : ModelAnimationCache.getSkinInverseBindMatrices(model, accessor), - bindShapeMatrix : bindShapeMatrix // not used when undefined - }; + var bindShapeMatrix; + if (!Matrix4.equals(skin.bindShapeMatrix, Matrix4.IDENTITY)) { + bindShapeMatrix = Matrix4.clone(skin.bindShapeMatrix); } - } + + runtimeSkins[id] = { + inverseBindMatrices : ModelAnimationCache.getSkinInverseBindMatrices(model, accessor), + bindShapeMatrix : bindShapeMatrix // not used when undefined + }; + }); createJoints(model, runtimeSkins); } @@ -2551,8 +2498,10 @@ define([ //if (targetPath === 'translation') { // return; //} - runtimeNode[targetPath] = spline.evaluate(localAnimationTime, runtimeNode[targetPath]); - runtimeNode.dirtyNumber = model._maxDirtyNumber; + if (defined(spline)) { + runtimeNode[targetPath] = spline.evaluate(localAnimationTime, runtimeNode[targetPath]); + runtimeNode.dirtyNumber = model._maxDirtyNumber; + } }; } @@ -2568,8 +2517,7 @@ define([ } loadResources.createRuntimeAnimations = false; - model._runtime.animations = { - }; + model._runtime.animations = {}; var runtimeNodes = model._runtime.nodes; var animations = model.gltf.animations; @@ -2579,17 +2527,8 @@ define([ if (animations.hasOwnProperty(animationId)) { var animation = animations[animationId]; var channels = animation.channels; - var parameters = animation.parameters; var samplers = animation.samplers; - var parameterValues = {}; - - for (var name in parameters) { - if (parameters.hasOwnProperty(name)) { - parameterValues[name] = ModelAnimationCache.getAnimationParameterValues(model, accessors[parameters[name]]); - } - } - // Find start and stop time for the entire animation var startTime = Number.MAX_VALUE; var stopTime = -Number.MAX_VALUE; @@ -2600,15 +2539,18 @@ define([ for (var i = 0; i < length; ++i) { var channel = channels[i]; var target = channel.target; + var path = target.path; var sampler = samplers[channel.sampler]; - var times = parameterValues[sampler.input]; + var input = ModelAnimationCache.getAnimationParameterValues(model, accessors[sampler.input]); + var output = ModelAnimationCache.getAnimationParameterValues(model, accessors[sampler.output]); + + startTime = Math.min(startTime, input[0]); + stopTime = Math.max(stopTime, input[input.length - 1]); - startTime = Math.min(startTime, times[0]); - stopTime = Math.max(stopTime, times[times.length - 1]); + var spline = ModelAnimationCache.getAnimationSpline(model, animationId, animation, channel.sampler, sampler, input, path, output); - var spline = ModelAnimationCache.getAnimationSpline(model, animationId, animation, channel.sampler, sampler, parameterValues); // GLTF_SPEC: Support more targets like materials. https://github.com/KhronosGroup/glTF/issues/142 - channelEvaluators[i] = getChannelEvaluator(model, runtimeNodes[target.id], target.path, spline); + channelEvaluators[i] = getChannelEvaluator(model, runtimeNodes[target.node], target.path, spline); } model._runtime.animations[animationId] = { @@ -2665,15 +2607,19 @@ define([ // with an attribute that wasn't used and the asset wasn't optimized. if (defined(attributeLocation)) { var a = accessors[primitiveAttributes[attributeName]]; + var normalize = false; + if (defined(a.normalized) && a.normalized) { + normalize = true; + } attributes.push({ index : attributeLocation, vertexBuffer : rendererBuffers[a.bufferView], - componentsPerAttribute : getBinaryAccessor(a).componentsPerAttribute, + componentsPerAttribute : numberOfComponentsForType(a.type), componentDatatype : a.componentType, - normalize : false, + normalize : normalize, offsetInBytes : a.byteOffset, - strideInBytes : a.byteStride + strideInBytes : getAccessorByteStride(gltf, a) }); } } @@ -2716,7 +2662,6 @@ define([ booleanStates[WebGLConstants.CULL_FACE] = false; booleanStates[WebGLConstants.DEPTH_TEST] = false; booleanStates[WebGLConstants.POLYGON_OFFSET_FILL] = false; - booleanStates[WebGLConstants.SCISSOR_TEST] = false; var enable = states.enable; var length = enable.length; @@ -2762,7 +2707,6 @@ define([ var colorMask = defaultValue(statesFunctions.colorMask, [true, true, true, true]); var depthRange = defaultValue(statesFunctions.depthRange, [0.0, 1.0]); var polygonOffset = defaultValue(statesFunctions.polygonOffset, [0.0, 0.0]); - var scissor = defaultValue(statesFunctions.scissor, [0.0, 0.0, 0.0, 0.0]); // Change the render state to use traditional alpha blending instead of premultiplied alpha blending if (booleanStates[WebGLConstants.BLEND] && hasPremultipliedAlpha(model)) { @@ -2786,15 +2730,6 @@ define([ factor : polygonOffset[0], units : polygonOffset[1] }, - scissorTest : { - enabled : booleanStates[WebGLConstants.SCISSOR_TEST], - rectangle : { - x : scissor[0], - y : scissor[1], - width : scissor[2], - height : scissor[3] - } - }, depthRange : { near : depthRange[0], far : depthRange[1] @@ -2997,7 +2932,7 @@ define([ function DelayLoadedTextureUniform(value, model) { this._value = undefined; - this._textureId = value; + this._textureId = value.index; this._model = model; } @@ -3181,7 +3116,8 @@ define([ for (var materialId in materials) { if (materials.hasOwnProperty(materialId)) { var material = materials[materialId]; - var instanceParameters = material.values; + var instanceParameters; + instanceParameters = material.values; var technique = techniques[material.technique]; var parameters = technique.parameters; var uniforms = technique.uniforms; @@ -3189,10 +3125,11 @@ define([ var uniformMap = {}; var uniformValues = {}; var jointMatrixUniformName; + var morphWeightsUniformName; // Uniform parameters for (var name in uniforms) { - if (uniforms.hasOwnProperty(name)) { + if (uniforms.hasOwnProperty(name) && name !== 'extras') { var parameterName = uniforms[name]; var parameter = parameters[parameterName]; @@ -3215,11 +3152,13 @@ define([ } else if (defined(parameter.node)) { uniformMap[name] = getUniformFunctionFromSource(parameter.node, model, parameter.semantic, context.uniformState); } else if (defined(parameter.semantic)) { - if (parameter.semantic !== 'JOINTMATRIX') { + if (parameter.semantic === 'JOINTMATRIX') { + jointMatrixUniformName = name; + } else if (parameter.semantic === 'MORPHWEIGHTS') { + morphWeightsUniformName = name; + } else { // Map glTF semantic to Cesium automatic uniform uniformMap[name] = gltfSemanticUniforms[parameter.semantic](context.uniformState, model); - } else { - jointMatrixUniformName = name; } } else if (defined(parameter.value)) { // Technique value that isn't overridden by a material @@ -3234,6 +3173,7 @@ define([ u.uniformMap = uniformMap; // uniform name -> function for the renderer u.values = uniformValues; // material parameter name -> ModelMaterial for modifying the parameter at runtime u.jointMatrixUniformName = jointMatrixUniformName; + u.morphWeightsUniformName = morphWeightsUniformName; } } } @@ -3263,6 +3203,10 @@ define([ var a = accessors[accessorId]; var extensions = a.extensions; + if (attribute.charAt(0) === '_') { + attribute = attribute.substring(1); + } + if (defined(extensions)) { var quantizedAttributes = extensions.WEB3D_quantized_attributes; if (defined(quantizedAttributes)) { @@ -3334,6 +3278,12 @@ define([ }; } + function createMorphWeightsFunction(runtimeNode) { + return function() { + return runtimeNode.weights; + }; + } + function createSilhouetteColorFunction(model) { return function() { return model.silhouetteColor; @@ -3389,93 +3339,137 @@ define([ var techniques = gltf.techniques; var materials = gltf.materials; - var meshes = gltfNode.meshes; - var meshesLength = meshes.length; + var id = gltfNode.mesh; + var mesh = gltfMeshes[id]; - for (var j = 0; j < meshesLength; ++j) { - var id = meshes[j]; - var mesh = gltfMeshes[id]; - var primitives = mesh.primitives; - var length = primitives.length; + var primitives = mesh.primitives; + var length = primitives.length; - // The glTF node hierarchy is a DAG so a node can have more than one - // parent, so a node may already have commands. If so, append more - // since they will have a different model matrix. + // The glTF node hierarchy is a DAG so a node can have more than one + // parent, so a node may already have commands. If so, append more + // since they will have a different model matrix. - for (var i = 0; i < length; ++i) { - var primitive = primitives[i]; - var ix = accessors[primitive.indices]; - var material = materials[primitive.material]; - var technique = techniques[material.technique]; - var programId = technique.program; + for (var i = 0; i < length; ++i) { + var primitive = primitives[i]; + var ix = accessors[primitive.indices]; + var material = materials[primitive.material]; + var technique = techniques[material.technique]; + var programId = technique.program; + + var boundingSphere; + var positionAccessor = primitive.attributes.POSITION; + if (defined(positionAccessor)) { + var minMax = getAccessorMinMax(gltf, positionAccessor); + boundingSphere = BoundingSphere.fromCornerPoints(Cartesian3.fromArray(minMax.min), Cartesian3.fromArray(minMax.max)); + } - var boundingSphere; - var positionAccessor = primitive.attributes.POSITION; - if (defined(positionAccessor)) { - var minMax = getAccessorMinMax(gltf, positionAccessor); - boundingSphere = BoundingSphere.fromCornerPoints(Cartesian3.fromArray(minMax.min), Cartesian3.fromArray(minMax.max)); - } + var vertexArray = rendererVertexArrays[id + '.primitive.' + i]; + var offset; + var count; + if (defined(ix)) { + count = ix.count; + offset = (ix.byteOffset / IndexDatatype.getSizeInBytes(ix.componentType)); // glTF has offset in bytes. Cesium has offsets in indices + } + else { + var positions = accessors[primitive.attributes.POSITION]; + count = positions.count; + offset = 0; + } - var vertexArray = rendererVertexArrays[id + '.primitive.' + i]; - var offset; - var count; - if (defined(ix)) { - count = ix.count; - offset = (ix.byteOffset / IndexDatatype.getSizeInBytes(ix.componentType)); // glTF has offset in bytes. Cesium has offsets in indices - } - else { - var positions = accessors[primitive.attributes.POSITION]; - count = positions.count; - offset = 0; - } + // Update model triangle count using number of indices + model._trianglesLength += triangleCountFromPrimitiveIndices(primitive, count); - // Update model triangle count using number of indices - model._trianglesLength += triangleCountFromPrimitiveIndices(primitive, count); + var um = uniformMaps[primitive.material]; + var uniformMap = um.uniformMap; + if (defined(um.jointMatrixUniformName)) { + var jointUniformMap = {}; + jointUniformMap[um.jointMatrixUniformName] = createJointMatricesFunction(runtimeNode); - var um = uniformMaps[primitive.material]; - var uniformMap = um.uniformMap; - if (defined(um.jointMatrixUniformName)) { - var jointUniformMap = {}; - jointUniformMap[um.jointMatrixUniformName] = createJointMatricesFunction(runtimeNode); + uniformMap = combine(uniformMap, jointUniformMap); + } + if (defined(um.morphWeightsUniformName)) { + var morphWeightsUniformMap = {}; + morphWeightsUniformMap[um.morphWeightsUniformName] = createMorphWeightsFunction(runtimeNode); - uniformMap = combine(uniformMap, jointUniformMap); - } + uniformMap = combine(uniformMap, morphWeightsUniformMap); + } - uniformMap = combine(uniformMap, { - gltf_color : createColorFunction(model), - gltf_colorBlend : createColorBlendFunction(model) - }); + uniformMap = combine(uniformMap, { + gltf_color : createColorFunction(model), + gltf_colorBlend : createColorBlendFunction(model) + }); - // Allow callback to modify the uniformMap - if (defined(model._uniformMapLoaded)) { - uniformMap = model._uniformMapLoaded(uniformMap, programId, runtimeNode); - } + // Allow callback to modify the uniformMap + if (defined(model._uniformMapLoaded)) { + uniformMap = model._uniformMapLoaded(uniformMap, programId, runtimeNode); + } - // Add uniforms for decoding quantized attributes if used - if (usesExtension(model, 'WEB3D_quantized_attributes')) { - var quantizedUniformMap = createUniformsForQuantizedAttributes(model, primitive, context); - uniformMap = combine(uniformMap, quantizedUniformMap); - } + // Add uniforms for decoding quantized attributes if used + if (model.extensionsUsed.WEB3D_quantized_attributes) { + var quantizedUniformMap = createUniformsForQuantizedAttributes(model, primitive, context); + uniformMap = combine(uniformMap, quantizedUniformMap); + } + + var rs = rendererRenderStates[material.technique]; - var rs = rendererRenderStates[material.technique]; + // GLTF_SPEC: Offical means to determine translucency. https://github.com/KhronosGroup/glTF/issues/105 + var isTranslucent = rs.blending.enabled; - // GLTF_SPEC: Offical means to determine translucency. https://github.com/KhronosGroup/glTF/issues/105 - var isTranslucent = rs.blending.enabled; + var owner = model._pickObject; + if (!defined(owner)) { + owner = { + primitive : model, + id : model.id, + node : runtimeNode.publicNode, + mesh : runtimeMeshesByName[mesh.name] + }; + } + + var castShadows = ShadowMode.castShadows(model._shadows); + var receiveShadows = ShadowMode.receiveShadows(model._shadows); + + var command = new DrawCommand({ + boundingVolume : new BoundingSphere(), // updated in update() + cull : model.cull, + modelMatrix : new Matrix4(), // computed in update() + primitiveType : primitive.mode, + vertexArray : vertexArray, + count : count, + offset : offset, + shaderProgram : rendererPrograms[technique.program], + castShadows : castShadows, + receiveShadows : receiveShadows, + uniformMap : uniformMap, + renderState : rs, + owner : owner, + pass : isTranslucent ? Pass.TRANSLUCENT : model.opaquePass + }); - var owner = model._pickObject; - if (!defined(owner)) { - owner = { - primitive : model, - id : model.id, - node : runtimeNode.publicNode, - mesh : runtimeMeshesByName[mesh.name] + var pickCommand; + + if (allowPicking) { + var pickUniformMap; + + // Callback to override default model picking + if (defined(model._pickFragmentShaderLoaded)) { + if (defined(model._pickUniformMapLoaded)) { + pickUniformMap = model._pickUniformMapLoaded(uniformMap); + } else { + // This is unlikely, but could happen if the override shader does not + // need new uniforms since, for example, its pick ids are coming from + // a vertex attribute or are baked into the shader source. + pickUniformMap = combine(uniformMap); + } + } else { + var pickId = context.createPickId(owner); + pickIds.push(pickId); + var pickUniforms = { + czm_pickColor : createPickColorFunction(pickId.color) }; + pickUniformMap = combine(uniformMap, pickUniforms); } - var castShadows = ShadowMode.castShadows(model._shadows); - var receiveShadows = ShadowMode.receiveShadows(model._shadows); - - var command = new DrawCommand({ + pickCommand = new DrawCommand({ boundingVolume : new BoundingSphere(), // updated in update() cull : model.cull, modelMatrix : new Matrix4(), // computed in update() @@ -3483,89 +3477,48 @@ define([ vertexArray : vertexArray, count : count, offset : offset, - shaderProgram : rendererPrograms[technique.program], - castShadows : castShadows, - receiveShadows : receiveShadows, - uniformMap : uniformMap, + shaderProgram : rendererPickPrograms[technique.program], + uniformMap : pickUniformMap, renderState : rs, owner : owner, pass : isTranslucent ? Pass.TRANSLUCENT : model.opaquePass }); + } - var pickCommand; + var command2D; + var pickCommand2D; + if (!scene3DOnly) { + command2D = DrawCommand.shallowClone(command); + command2D.boundingVolume = new BoundingSphere(); // updated in update() + command2D.modelMatrix = new Matrix4(); // updated in update() if (allowPicking) { - var pickUniformMap; - - // Callback to override default model picking - if (defined(model._pickFragmentShaderLoaded)) { - if (defined(model._pickUniformMapLoaded)) { - pickUniformMap = model._pickUniformMapLoaded(uniformMap); - } else { - // This is unlikely, but could happen if the override shader does not - // need new uniforms since, for example, its pick ids are coming from - // a vertex attribute or are baked into the shader source. - pickUniformMap = combine(uniformMap); - } - } else { - var pickId = context.createPickId(owner); - pickIds.push(pickId); - var pickUniforms = { - czm_pickColor : createPickColorFunction(pickId.color) - }; - pickUniformMap = combine(uniformMap, pickUniforms); - } - - pickCommand = new DrawCommand({ - boundingVolume : new BoundingSphere(), // updated in update() - cull : model.cull, - modelMatrix : new Matrix4(), // computed in update() - primitiveType : primitive.mode, - vertexArray : vertexArray, - count : count, - offset : offset, - shaderProgram : rendererPickPrograms[technique.program], - uniformMap : pickUniformMap, - renderState : rs, - owner : owner, - pass : isTranslucent ? Pass.TRANSLUCENT : model.opaquePass - }); - } - - var command2D; - var pickCommand2D; - if (!scene3DOnly) { - command2D = DrawCommand.shallowClone(command); - command2D.boundingVolume = new BoundingSphere(); // updated in update() - command2D.modelMatrix = new Matrix4(); // updated in update() - - if (allowPicking) { - pickCommand2D = DrawCommand.shallowClone(pickCommand); - pickCommand2D.boundingVolume = new BoundingSphere(); // updated in update() - pickCommand2D.modelMatrix = new Matrix4(); // updated in update() - } + pickCommand2D = DrawCommand.shallowClone(pickCommand); + pickCommand2D.boundingVolume = new BoundingSphere(); // updated in update() + pickCommand2D.modelMatrix = new Matrix4(); // updated in update() } - - var nodeCommand = { - show : true, - boundingSphere : boundingSphere, - command : command, - pickCommand : pickCommand, - command2D : command2D, - pickCommand2D : pickCommand2D, - // Generated on demand when silhouette size is greater than 0.0 and silhouette alpha is greater than 0.0 - silhouetteModelCommand : undefined, - silhouetteModelCommand2D : undefined, - silhouetteColorCommand : undefined, - silhouetteColorCommand2D : undefined, - // Generated on demand when color alpha is less than 1.0 - translucentCommand : undefined, - translucentCommand2D : undefined - }; - runtimeNode.commands.push(nodeCommand); - nodeCommands.push(nodeCommand); } + + var nodeCommand = { + show : true, + boundingSphere : boundingSphere, + command : command, + pickCommand : pickCommand, + command2D : command2D, + pickCommand2D : pickCommand2D, + // Generated on demand when silhouette size is greater than 0.0 and silhouette alpha is greater than 0.0 + silhouetteModelCommand : undefined, + silhouetteModelCommand2D : undefined, + silhouetteColorCommand : undefined, + silhouetteColorCommand2D : undefined, + // Generated on demand when color alpha is less than 1.0 + translucentCommand : undefined, + translucentCommand2D : undefined + }; + runtimeNode.commands.push(nodeCommand); + nodeCommands.push(nodeCommand); } + } function createRuntimeNodes(model, context, scene3DOnly) { @@ -3585,12 +3538,14 @@ define([ var gltf = model.gltf; var nodes = gltf.nodes; + var skins = gltf.skins; var scene = gltf.scenes[gltf.scene]; var sceneNodes = scene.nodes; var length = sceneNodes.length; var stack = []; + var seen = {}; for (var i = 0; i < length; ++i) { stack.push({ @@ -3599,8 +3554,10 @@ define([ id : sceneNodes[i] }); + var skeletonIds = []; while (stack.length > 0) { var n = stack.pop(); + seen[n.id] = true; var parentRuntimeNode = n.parentRuntimeNode; var gltfNode = n.gltfNode; @@ -3625,18 +3582,39 @@ define([ rootNodes.push(runtimeNode); } - if (defined(gltfNode.meshes)) { + if (defined(gltfNode.mesh)) { createCommand(model, gltfNode, runtimeNode, context, scene3DOnly); } var children = gltfNode.children; var childrenLength = children.length; - for (var k = 0; k < childrenLength; ++k) { - stack.push({ - parentRuntimeNode : runtimeNode, - gltfNode : nodes[children[k]], - id : children[k] - }); + for (var j = 0; j < childrenLength; j++) { + var childId = children[j]; + if (!seen[childId]) { + stack.push({ + parentRuntimeNode : runtimeNode, + gltfNode : nodes[childId], + id : children[j] + }); + } + } + + var skin = gltfNode.skin; + if (defined(skin)) { + skeletonIds.push(skins[skin].skeleton); + } + + if (stack.length === 0) { + for (var k = 0; k < skeletonIds.length; k++) { + var skeleton = skeletonIds[k]; + if (!seen[skeleton]) { + stack.push({ + parentRuntimeNode : undefined, + gltfNode : nodes[skeleton], + id : skeleton + }); + } + } } } } @@ -3669,6 +3647,7 @@ define([ var context = frameState.context; var scene3DOnly = frameState.scene3DOnly; + checkSupportedGlExtensions(model, context); if (model._loadRendererResourcesFromCache) { var resources = model._rendererResources; var cachedResources = model._cachedRendererResources; @@ -3777,7 +3756,7 @@ define([ var commandsLength = commands.length; if (commandsLength > 0) { // Node has meshes, which has primitives. Update their commands. - for (var j = 0 ; j < commandsLength; ++j) { + for (var j = 0; j < commandsLength; ++j) { var primitiveCommand = commands[j]; var command = primitiveCommand.command; Matrix4.clone(nodeMatrix, command.modelMatrix); @@ -3897,7 +3876,7 @@ define([ var nodeCommands = n.commands; var nodeCommandsLength = nodeCommands.length; - for (var j = 0 ; j < nodeCommandsLength; ++j) { + for (var j = 0; j < nodeCommandsLength; ++j) { nodeCommands[j].show = show; } // if commandsLength is zero, the node has a light or camera @@ -4291,20 +4270,35 @@ define([ } function checkSupportedExtensions(model) { - var extensionsUsed = model.gltf.extensionsUsed; - if (defined(extensionsUsed)) { - var extensionsUsedCount = extensionsUsed.length; - for (var index = 0; index < extensionsUsedCount; ++index) { - var extension = extensionsUsed[index]; - - if (extension !== 'CESIUM_RTC' && extension !== 'KHR_binary_glTF' && - extension !== 'KHR_materials_common' && extension !== 'WEB3D_quantized_attributes') { + var extensionsRequired = model.extensionsRequired; + for (var extension in extensionsRequired) { + if (extensionsRequired.hasOwnProperty(extension)) { + if (extension !== 'CESIUM_RTC' && + extension !== 'KHR_technique_webgl' && + extension !== 'KHR_binary_glTF' && + extension !== 'KHR_materials_common' && + extension !== 'WEB3D_quantized_attributes') { throw new RuntimeError('Unsupported glTF Extension: ' + extension); } } } } + function checkSupportedGlExtensions(model, context) { + var glExtensionsUsed = model.gltf.glExtensionsUsed; + if (defined(glExtensionsUsed)) { + var glExtensionsUsedLength = glExtensionsUsed.length; + for (var i = 0; i < glExtensionsUsedLength; i++) { + var extension = glExtensionsUsed[i]; + if (extension !== 'OES_element_index_uint') { + throw new RuntimeError('Unsupported WebGL Extension: ' + extension); + } else if (!context.elementIndexUint) { + throw new RuntimeError('OES_element_index_uint WebGL extension is not enabled.'); + } + } + } + } + /////////////////////////////////////////////////////////////////////////// function CachedRendererResources(context, cacheKey) { @@ -4356,7 +4350,7 @@ define([ /////////////////////////////////////////////////////////////////////////// function getUpdateHeightCallback(model, ellipsoid, cartoPosition) { - return function (clampedPosition) { + return function(clampedPosition) { if (model.heightReference === HeightReference.RELATIVE_TO_GROUND) { var clampedCart = ellipsoid.cartesianToCartographic(clampedPosition, scratchCartographic); clampedCart.height += cartoPosition.height; @@ -4502,11 +4496,6 @@ define([ } this._state = ModelState.LOADING; - - this._boundingSphere = computeBoundingSphere(this, this.gltf); - this._initialRadius = this._boundingSphere.radius; - - checkSupportedExtensions(this); if (this._state !== ModelState.FAILED) { var extensions = this.gltf.extensions; if (defined(extensions) && defined(extensions.CESIUM_RTC)) { @@ -4527,7 +4516,10 @@ define([ } this._loadResources = new LoadResources(); - parse(this, context); + if (!this._loadRendererResourcesFromCache) { + // Buffers are required to updateVersion + parseBuffers(this); + } } } @@ -4536,13 +4528,45 @@ define([ var justLoaded = false; if (this._state === ModelState.LOADING) { - // Create WebGL resources as buffers/shaders/textures are downloaded - createResources(this, frameState); - // Transition from LOADING -> LOADED once resources are downloaded and created. // Textures may continue to stream in while in the LOADED state. + if (loadResources.pendingBufferLoads === 0) { + if (!this._updatedGltfVersion) { + var options = { + optimizeForCesium: true, + addBatchIdToGeneratedShaders : this._addBatchIdToGeneratedShaders + }; + frameState.brdfLutGenerator.update(frameState); + updateVersion(this.gltf); + checkSupportedExtensions(this); + addPipelineExtras(this.gltf); + addDefaults(this.gltf); + processModelMaterialsCommon(this.gltf, options); + processPbrMetallicRoughness(this.gltf, options); + // We do this after to make sure that the ids don't change + addBuffersToLoadResources(this); + this._animationIds = getAnimationIds(this.gltf); + + if (!this._loadRendererResourcesFromCache) { + parseBufferViews(this); + parseShaders(this); + parsePrograms(this); + parseTextures(this, context); + } + parseMaterials(this); + parseMeshes(this); + parseNodes(this); + + this._boundingSphere = computeBoundingSphere(this); + this._initialRadius = this._boundingSphere.radius; + this._updatedGltfVersion = true; + } + if (this._updatedGltfVersion && loadResources.pendingShaderLoads === 0) { + createResources(this, frameState); + } + } if (loadResources.finished() || - (incrementallyLoadTextures && loadResources.finishedEverythingButTextureCreation())) { + (incrementallyLoadTextures && loadResources.finishedEverythingButTextureCreation())) { this._state = ModelState.LOADED; justLoaded = true; } @@ -4550,7 +4574,6 @@ define([ // Incrementally stream textures. if (defined(loadResources) && (this._state === ModelState.LOADED)) { - // Also check justLoaded so we don't process twice during the transition frame if (incrementallyLoadTextures && !justLoaded) { createResources(this, frameState); } @@ -4570,6 +4593,7 @@ define([ cachedResources.samplers = resources.samplers; cachedResources.renderStates = resources.renderStates; cachedResources.ready = true; + removePipelineExtras(this.gltf); // The normal attribute name is required for silhouettes, so get it before the gltf JSON is released this._normalAttributeName = getAttributeOrUniformBySemantic(this.gltf, 'NORMAL'); diff --git a/Source/Scene/ModelAnimationCache.js b/Source/Scene/ModelAnimationCache.js index 8a4f9a581533..edcee52f8bfa 100644 --- a/Source/Scene/ModelAnimationCache.js +++ b/Source/Scene/ModelAnimationCache.js @@ -1,23 +1,31 @@ define([ + './AttributeType', '../Core/Cartesian3', + '../Core/ComponentDatatype', + '../Core/defaultValue', '../Core/defined', '../Core/LinearSpline', '../Core/Matrix4', '../Core/Quaternion', '../Core/QuaternionSpline', '../Core/WebGLConstants', - './AttributeType', - './getBinaryAccessor' + '../Core/WeightSpline', + '../ThirdParty/GltfPipeline/getAccessorByteStride', + '../ThirdParty/GltfPipeline/numberOfComponentsForType' ], function( + AttributeType, Cartesian3, + ComponentDatatype, + defaultValue, defined, LinearSpline, Matrix4, Quaternion, QuaternionSpline, WebGLConstants, - AttributeType, - getBinaryAccessor) { + WeightSpline, + getAccessorByteStride, + numberOfComponentsForType) { 'use strict'; /** @@ -37,7 +45,7 @@ define([ var buffer = buffers[bufferView.buffer]; var byteOffset = bufferView.byteOffset + accessor.byteOffset; - var byteLength = accessor.count * getBinaryAccessor(accessor).componentsPerAttribute; + var byteLength = accessor.count * numberOfComponentsForType(accessor.type); var uriKey = dataUriRegex.test(buffer.uri) ? '' : buffer.uri; return model.cacheKey + '//' + uriKey + '/' + byteOffset + '/' + byteLength; @@ -46,50 +54,41 @@ define([ var cachedAnimationParameters = { }; - var axisScratch = new Cartesian3(); - ModelAnimationCache.getAnimationParameterValues = function(model, accessor) { var key = getAccessorKey(model, accessor); var values = cachedAnimationParameters[key]; if (!defined(values)) { // Cache miss - var loadResources = model._loadResources; var gltf = model.gltf; - var hasAxisAngle = (parseFloat(gltf.asset.version) < 1.0); + var buffers = gltf.buffers; var bufferViews = gltf.bufferViews; var bufferView = bufferViews[accessor.bufferView]; + var bufferId = bufferView.buffer; + var buffer = buffers[bufferId]; + var source = buffer.extras._pipeline.source; var componentType = accessor.componentType; var type = accessor.type; + var numberOfComponents = numberOfComponentsForType(type); var count = accessor.count; - - // Convert typed array to Cesium types - var buffer = loadResources.getBuffer(bufferView); - var typedArray = getBinaryAccessor(accessor).createArrayBufferView(buffer.buffer, buffer.byteOffset + accessor.byteOffset, count); - var i; - - if ((componentType === WebGLConstants.FLOAT) && (type === AttributeType.SCALAR)) { - values = typedArray; - } - else if ((componentType === WebGLConstants.FLOAT) && (type === AttributeType.VEC3)) { - values = new Array(count); - for (i = 0; i < count; ++i) { - values[i] = Cartesian3.fromArray(typedArray, 3 * i); - } - } else if ((componentType === WebGLConstants.FLOAT) && (type === AttributeType.VEC4)) { - values = new Array(count); - for (i = 0; i < count; ++i) { - var byteOffset = 4 * i; - if (hasAxisAngle) { - values[i] = Quaternion.fromAxisAngle(Cartesian3.fromArray(typedArray, byteOffset, axisScratch), typedArray[byteOffset + 3]); - } - else { - values[i] = Quaternion.unpack(typedArray, byteOffset); - } + var byteStride = getAccessorByteStride(gltf, accessor); + + values = new Array(count); + var accessorByteOffset = defaultValue(accessor.byteOffset, 0); + var byteOffset = bufferView.byteOffset + accessorByteOffset; + for (var i = 0; i < count; i++) { + var typedArrayView = ComponentDatatype.createArrayBufferView(componentType, source.buffer, byteOffset, numberOfComponents); + if (type === 'SCALAR') { + values[i] = typedArrayView[0]; + } else if (type === 'VEC3') { + values[i] = Cartesian3.fromArray(typedArrayView); + } else if (type === 'VEC4') { + values[i] = Quaternion.unpack(typedArrayView); } + byteOffset += byteStride; } // GLTF_SPEC: Support more parameter types when glTF supports targeting materials. https://github.com/KhronosGroup/glTF/issues/142 @@ -109,47 +108,41 @@ define([ return model.cacheKey + '//' + animationName + '/' + samplerName; } - // GLTF_SPEC: https://github.com/KhronosGroup/glTF/issues/185 function ConstantSpline(value) { this._value = value; } ConstantSpline.prototype.evaluate = function(time, result) { return this._value; }; - // END GLTF_SPEC - ModelAnimationCache.getAnimationSpline = function(model, animationName, animation, samplerName, sampler, parameterValues) { + ModelAnimationCache.getAnimationSpline = function(model, animationName, animation, samplerName, sampler, input, path, output) { var key = getAnimationSplineKey(model, animationName, samplerName); var spline = cachedAnimationSplines[key]; if (!defined(spline)) { - var times = parameterValues[sampler.input]; - var accessor = model.gltf.accessors[animation.parameters[sampler.output]]; - var controlPoints = parameterValues[sampler.output]; + var times = input; + var controlPoints = output; -// GLTF_SPEC: https://github.com/KhronosGroup/glTF/issues/185 if ((times.length === 1) && (controlPoints.length === 1)) { spline = new ConstantSpline(controlPoints[0]); - } else { -// END GLTF_SPEC - var componentType = accessor.componentType; - var type = accessor.type; - - if (sampler.interpolation === 'LINEAR') { - if ((componentType === WebGLConstants.FLOAT) && (type === AttributeType.VEC3)) { - spline = new LinearSpline({ - times : times, - points : controlPoints - }); - } else if ((componentType === WebGLConstants.FLOAT) && (type === AttributeType.VEC4)) { - spline = new QuaternionSpline({ - times : times, - points : controlPoints - }); - } - // GLTF_SPEC: Support more parameter types when glTF supports targeting materials. https://github.com/KhronosGroup/glTF/issues/142 + } else if (sampler.interpolation === 'LINEAR') { + if (path === 'translation' || path === 'scale') { + spline = new LinearSpline({ + times : times, + points : controlPoints + }); + } else if (path === 'rotation') { + spline = new QuaternionSpline({ + times : times, + points : controlPoints + }); + } else if (path === 'weights') { + spline = new WeightSpline({ + times : times, + weights : controlPoints + }); } - // GLTF_SPEC: Support new interpolators. https://github.com/KhronosGroup/glTF/issues/156 + // GLTF_SPEC: Support more parameter types when glTF supports targeting materials. https://github.com/KhronosGroup/glTF/issues/142 } if (defined(model.cacheKey)) { @@ -170,23 +163,30 @@ define([ if (!defined(matrices)) { // Cache miss - - var loadResources = model._loadResources; var gltf = model.gltf; + var buffers = gltf.buffers; var bufferViews = gltf.bufferViews; - var bufferView = bufferViews[accessor.bufferView]; + var bufferViewId = accessor.bufferView; + var bufferView = bufferViews[bufferViewId]; + var bufferId = bufferView.buffer; + var buffer = buffers[bufferId]; + var source = buffer.extras._pipeline.source; var componentType = accessor.componentType; var type = accessor.type; var count = accessor.count; - var buffer = loadResources.getBuffer(bufferView); - var typedArray = getBinaryAccessor(accessor).createArrayBufferView(buffer.buffer, buffer.byteOffset + accessor.byteOffset, count); - matrices = new Array(count); + var byteStride = getAccessorByteStride(gltf, accessor); + var byteOffset = bufferView.byteOffset + accessor.byteOffset; + var numberOfComponents = numberOfComponentsForType(type); + + matrices = new Array(count); if ((componentType === WebGLConstants.FLOAT) && (type === AttributeType.MAT4)) { for (var i = 0; i < count; ++i) { - matrices[i] = Matrix4.fromArray(typedArray, 16 * i); + var typedArrayView = ComponentDatatype.createArrayBufferView(componentType, source.buffer, byteOffset, numberOfComponents); + matrices[i] = Matrix4.fromArray(typedArrayView); + byteOffset += byteStride; } } diff --git a/Source/Scene/ModelAnimationCollection.js b/Source/Scene/ModelAnimationCollection.js index b2603afb5821..0ce83970ac46 100644 --- a/Source/Scene/ModelAnimationCollection.js +++ b/Source/Scene/ModelAnimationCollection.js @@ -212,7 +212,6 @@ define([ options.name = animationIds[i]; scheduledAnimations.push(this.add(options)); } - return scheduledAnimations; }; diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js index f99853f1ac4e..7ce1b5d96d5d 100644 --- a/Source/Scene/Scene.js +++ b/Source/Scene/Scene.js @@ -2,6 +2,7 @@ define([ '../Core/BoundingRectangle', '../Core/BoundingSphere', '../Core/BoxGeometry', + '../Core/buildModuleUrl', '../Core/Cartesian2', '../Core/Cartesian3', '../Core/Cartesian4', @@ -42,13 +43,16 @@ define([ '../Renderer/ContextLimits', '../Renderer/DrawCommand', '../Renderer/Framebuffer', + '../Renderer/loadCubeMap', '../Renderer/Pass', '../Renderer/PassState', '../Renderer/PixelDatatype', '../Renderer/RenderState', + '../Renderer/Sampler', '../Renderer/ShaderProgram', '../Renderer/ShaderSource', '../Renderer/Texture', + './BrdfLutGenerator', './Camera', './CreditDisplay', './DebugCameraPrimitive', @@ -78,6 +82,7 @@ define([ BoundingRectangle, BoundingSphere, BoxGeometry, + buildModuleUrl, Cartesian2, Cartesian3, Cartesian4, @@ -118,13 +123,16 @@ define([ ContextLimits, DrawCommand, Framebuffer, + loadCubeMap, Pass, PassState, PixelDatatype, RenderState, + Sampler, ShaderProgram, ShaderSource, Texture, + BrdfLutGenerator, Camera, CreditDisplay, DebugCameraPrimitive, @@ -623,6 +631,8 @@ define([ enabled : defaultValue(options.shadows, false) }); + this._brdfLutGenerator = new BrdfLutGenerator(); + this._terrainExaggeration = defaultValue(options.terrainExaggeration, 1.0); this._performanceDisplay = undefined; @@ -1279,6 +1289,8 @@ define([ var frameState = scene._frameState; frameState.commandList.length = 0; frameState.shadowMaps.length = 0; + frameState.brdfLutGenerator = scene._brdfLutGenerator; + frameState.environmentMap = scene.skyBox && scene.skyBox._cubeMap; frameState.mode = scene._mode; frameState.morphTime = scene.morphTime; frameState.mapProjection = scene.mapProjection; @@ -3327,6 +3339,7 @@ define([ this._depthPlane = this._depthPlane && this._depthPlane.destroy(); this._transitioner.destroy(); this._debugFrustumPlanes = this._debugFrustumPlanes && this._debugFrustumPlanes.destroy(); + this._brdfLutGenerator = this._brdfLutGenerator && this._brdfLutGenerator.destroy(); if (defined(this._globeDepth)) { this._globeDepth.destroy(); diff --git a/Source/Scene/TimeDynamicImagery.js b/Source/Scene/TimeDynamicImagery.js index 8d2de9a10be4..f51f38657fc0 100644 --- a/Source/Scene/TimeDynamicImagery.js +++ b/Source/Scene/TimeDynamicImagery.js @@ -1,4 +1,3 @@ -/*global define*/ define([ '../Core/Check', '../Core/defaultValue', diff --git a/Source/Scene/getAttributeOrUniformBySemantic.js b/Source/Scene/getAttributeOrUniformBySemantic.js index 6afe2bb935e9..b30affe7240b 100644 --- a/Source/Scene/getAttributeOrUniformBySemantic.js +++ b/Source/Scene/getAttributeOrUniformBySemantic.js @@ -1,4 +1,7 @@ -define([], function() { +define([ + '../Core/defined' + ], function( + defined) { 'use strict'; /** @@ -8,6 +11,7 @@ define([], function() { */ function getAttributeOrUniformBySemantic(gltf, semantic) { var techniques = gltf.techniques; + var parameter; for (var techniqueName in techniques) { if (techniques.hasOwnProperty(techniqueName)) { var technique = techniques[techniqueName]; @@ -16,14 +20,16 @@ define([], function() { var uniforms = technique.uniforms; for (var attributeName in attributes) { if (attributes.hasOwnProperty(attributeName)) { - if (parameters[attributes[attributeName]].semantic === semantic) { + parameter = parameters[attributes[attributeName]]; + if (defined(parameter) && parameter.semantic === semantic) { return attributeName; } } } for (var uniformName in uniforms) { if (uniforms.hasOwnProperty(uniformName)) { - if (parameters[uniforms[uniformName]].semantic === semantic) { + parameter = parameters[uniforms[uniformName]]; + if (defined(parameter) && parameter.semantic === semantic) { return uniformName; } } diff --git a/Source/Shaders/BrdfLutGeneratorFS.glsl b/Source/Shaders/BrdfLutGeneratorFS.glsl new file mode 100644 index 000000000000..9a432f1086f2 --- /dev/null +++ b/Source/Shaders/BrdfLutGeneratorFS.glsl @@ -0,0 +1,83 @@ +varying vec2 v_textureCoordinates; +const float M_PI = 3.141592653589793; + +float vdcRadicalInverse(int i) +{ + float r; + float base = 2.0; + float value = 0.0; + float invBase = 1.0 / base; + float invBi = invBase; + for (int x = 0; x < 100; x++) + { + if (i <= 0) + { + break; + } + r = mod(float(i), base); + value += r * invBi; + invBi *= invBase; + i = int(float(i) * invBase); + } + return value; +} + +vec2 hammersley2D(int i, int N) +{ + return vec2(float(i) / float(N), vdcRadicalInverse(i)); +} + +vec3 importanceSampleGGX(vec2 xi, float roughness, vec3 N) +{ + float a = roughness * roughness; + float phi = 2.0 * M_PI * xi.x; + float cosTheta = sqrt((1.0 - xi.y) / (1.0 + (a * a - 1.0) * xi.y)); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); + vec3 upVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangentX = normalize(cross(upVector, N)); + vec3 tangentY = cross(N, tangentX); + return tangentX * H.x + tangentY * H.y + N * H.z; +} + +float G1_Smith(float NdotV, float k) +{ + return NdotV / (NdotV * (1.0 - k) + k); +} + +float G_Smith(float roughness, float NdotV, float NdotL) +{ + float k = roughness * roughness / 2.0; + return G1_Smith(NdotV, k) * G1_Smith(NdotL, k); +} + +vec2 integrateBrdf(float roughness, float NdotV) +{ + vec3 V = vec3(sqrt(1.0 - NdotV * NdotV), 0.0, NdotV); + float A = 0.0; + float B = 0.0; + const int NumSamples = 1024; + for (int i = 0; i < NumSamples; i++) + { + vec2 xi = hammersley2D(i, NumSamples); + vec3 H = importanceSampleGGX(xi, roughness, vec3(0.0, 0.0, 1.0)); + vec3 L = 2.0 * dot(V, H) * H - V; + float NdotL = clamp(L.z, 0.0, 1.0); + float NdotH = clamp(H.z, 0.0, 1.0); + float VdotH = clamp(dot(V, H), 0.0, 1.0); + if (NdotL > 0.0) + { + float G = G_Smith(roughness, NdotV, NdotL); + float G_Vis = G * VdotH / (NdotH * NdotV); + float Fc = pow(1.0 - VdotH, 5.0); + A += (1.0 - Fc) * G_Vis; + B += Fc * G_Vis; + } + } + return vec2(A, B) / float(NumSamples); +} + +void main() +{ + gl_FragColor = vec4(integrateBrdf(1.0 - v_textureCoordinates.y, v_textureCoordinates.x), 0.0, 1.0); +} diff --git a/Source/ThirdParty/GltfPipeline/ForEach.js b/Source/ThirdParty/GltfPipeline/ForEach.js new file mode 100644 index 000000000000..814af92e5e7b --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/ForEach.js @@ -0,0 +1,215 @@ +define([ + '../../Core/defined' + ], function( + defined) { + 'use strict'; + + /** + * Contains traversal functions for processing elements of the glTF hierarchy. + * @constructor + */ + function ForEach() {} + + ForEach.object = function(arrayOfObjects, handler) { + if (defined(arrayOfObjects)) { + for (var i = 0; i < arrayOfObjects.length; i++) { + var object = arrayOfObjects[i]; + var returnValue = handler(object, i); + if (typeof returnValue === 'number') { + i += returnValue; + } + else if (returnValue) { + break; + } + } + } + }; + + ForEach.topLevel = function(gltf, name, handler) { + var arrayOfObjects = gltf[name]; + ForEach.object(arrayOfObjects, handler); + }; + + ForEach.accessor = function(gltf, handler) { + ForEach.topLevel(gltf, 'accessors', handler); + }; + + ForEach.accessorWithSemantic = function(gltf, semantic, handler) { + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + ForEach.meshPrimitiveAttribute(primitive, function(accessorId, attributeSemantic) { + if (attributeSemantic.indexOf(semantic) === 0) { + handler(accessorId, attributeSemantic, primitive); + } + }); + }); + }); + }; + + ForEach.animation = function(gltf, handler) { + ForEach.topLevel(gltf, 'animations', handler); + }; + + ForEach.animationSampler = function(animation, handler) { + var samplers = animation.samplers; + if (defined(samplers)) { + ForEach.object(samplers, handler); + } + }; + + ForEach.buffer = function(gltf, handler) { + ForEach.topLevel(gltf, 'buffers', handler); + }; + + ForEach.bufferView = function(gltf, handler) { + ForEach.topLevel(gltf, 'bufferViews', handler); + }; + + ForEach.camera = function(gltf, handler) { + ForEach.topLevel(gltf, 'cameras', handler); + }; + + ForEach.image = function(gltf, handler) { + ForEach.topLevel(gltf, 'images', handler); + }; + + ForEach.material = function(gltf, handler) { + ForEach.topLevel(gltf, 'materials', handler); + }; + + ForEach.materialValue = function(material, handler) { + var values = material.values; + if (defined(values)) { + for (var name in values) { + if (values.hasOwnProperty(name)) { + handler(values[name], name); + } + } + } + }; + + ForEach.mesh = function(gltf, handler) { + ForEach.topLevel(gltf, 'meshes', handler); + }; + + ForEach.meshPrimitive = function(mesh, handler) { + var primitives = mesh.primitives; + if (defined(primitives)) { + var primitivesLength = primitives.length; + for (var i = 0; i < primitivesLength; i++) { + var primitive = primitives[i]; + handler(primitive, i); + } + } + }; + + ForEach.meshPrimitiveAttribute = function(primitive, handler) { + var attributes = primitive.attributes; + if (defined(attributes)) { + for (var semantic in attributes) { + if (attributes.hasOwnProperty(semantic)) { + handler(attributes[semantic], semantic); + } + } + } + }; + + ForEach.meshPrimitiveTargetAttribute = function(primitive, handler) { + var targets = primitive.targets; + if (defined(targets)) { + for (var targetId in targets) { + if (targets.hasOwnProperty(targetId)) { + var target = targets[targetId]; + for (var attributeId in target) { + if (target.hasOwnProperty(attributeId) && attributeId !== 'extras') { + handler(target[attributeId], attributeId); + } + } + } + } + } + }; + + ForEach.node = function(gltf, handler) { + ForEach.topLevel(gltf, 'nodes', handler); + }; + + ForEach.nodeInTree = function(gltf, nodeIds, handler) { + var nodes = gltf.nodes; + if (defined(nodes)) { + for (var i = 0; i < nodeIds.length; i++) { + var nodeId = nodeIds[i]; + var node = nodes[nodeId]; + if (defined(node)) { + handler(node, nodeId); + var children = node.children; + if (defined(children)) { + ForEach.nodeInTree(gltf, children, handler); + } + } + } + } + }; + + ForEach.nodeInScene = function(gltf, scene, handler) { + var sceneNodeIds = scene.nodes; + if (defined(sceneNodeIds)) { + ForEach.nodeInTree(gltf, sceneNodeIds, handler); + } + }; + + ForEach.program = function(gltf, handler) { + ForEach.topLevel(gltf, 'programs', handler); + }; + + ForEach.sampler = function(gltf, handler) { + ForEach.topLevel(gltf, 'samplers', handler); + }; + + ForEach.scene = function(gltf, handler) { + ForEach.topLevel(gltf, 'scenes', handler); + }; + + ForEach.shader = function(gltf, handler) { + ForEach.topLevel(gltf, 'shaders', handler); + }; + + ForEach.skin = function(gltf, handler) { + ForEach.topLevel(gltf, 'skins', handler); + }; + + ForEach.techniqueAttribute = function(technique, handler) { + var attributes = technique.attributes; + if (defined(attributes)) { + for (var semantic in attributes) { + if (attributes.hasOwnProperty(semantic)) { + if (handler(attributes[semantic], semantic)) { + break; + } + } + } + } + }; + + ForEach.techniqueParameter = function(technique, handler) { + var parameters = technique.parameters; + if (defined(parameters)) { + for (var parameterName in parameters) { + if (parameters.hasOwnProperty(parameterName)) { + if (handler(parameters[parameterName], parameterName)) { + break; + } + } + } + } + }; + + ForEach.technique = function(gltf, handler) { + ForEach.topLevel(gltf, 'techniques', handler); + }; + + ForEach.texture = function(gltf, handler) { + ForEach.topLevel(gltf, 'textures', handler); + }; + return ForEach; +}); diff --git a/Source/ThirdParty/GltfPipeline/addDefaults.js b/Source/ThirdParty/GltfPipeline/addDefaults.js new file mode 100644 index 000000000000..edb4f5d80ef9 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/addDefaults.js @@ -0,0 +1,498 @@ +define([ + './addToArray', + './ForEach', + '../../Core/clone', + '../../Core/defaultValue', + '../../Core/defined', + '../../Core/WebGLConstants' + ], function( + addToArray, + ForEach, + clone, + defaultValue, + defined, + WebGLConstants) { + 'use strict'; + + var gltfTemplate = { + accessors: [], + animations : [ + { + channels : [], + samplers : [ + { + interpolation : 'LINEAR' + } + ] + } + ], + asset : {}, + buffers : [ + { + byteLength: 0, + type: 'arraybuffer' + } + ], + bufferViews: [ + { + byteLength: 0 + } + ], + cameras: [], + images: [], + materials: [ + { + values: function(material) { + var extensions = defaultValue(material.extensions, {}); + var materialsCommon = extensions.KHR_materials_common; + if (!defined(materialsCommon)) { + return {}; + } + }, + extensions: function(material) { + var extensions = defaultValue(material.extensions, {}); + var materialsCommon = extensions.KHR_materials_common; + if (defined(materialsCommon)) { + var technique = materialsCommon.technique; + var defaults = { + ambient: [0.0, 0.0, 0.0, 1.0], + emission: [0.0, 0.0, 0.0, 1.0], + transparency: [1.0] + }; + if (technique !== 'CONSTANT') { + defaults.diffuse = [0.0, 0.0, 0.0, 1.0]; + if (technique !== 'LAMBERT') { + defaults.specular = [0.0, 0.0, 0.0, 1.0]; + defaults.shininess = [0.0]; + } + } + return { + KHR_materials_common: { + doubleSided: false, + transparent: false, + values: defaults + } + }; + } + } + } + ], + meshes : [ + { + primitives : [ + { + attributes : {}, + mode : WebGLConstants.TRIANGLES + } + ] + } + ], + nodes : [ + { + children : [], + matrix : function(node) { + if (!defined(node.translation) && !defined(node.rotation) && !defined(node.scale)) { + return [ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ]; + } + }, + rotation : function(node) { + if (defined(node.translation) || defined(node.scale)) { + return [0.0, 0.0, 0.0, 1.0]; + } + }, + scale : function(node) { + if (defined(node.translation) || defined(node.rotation)) { + return [1.0, 1.0, 1.0]; + } + }, + translation : function(node) { + if (defined(node.rotation) || defined(node.scale)) { + return [0.0, 0.0, 0.0]; + } + } + } + ], + programs : [ + { + attributes : [] + } + ], + samplers : [ + { + magFilter: WebGLConstants.LINEAR, + minFilter : WebGLConstants.NEAREST_MIPMAP_LINEAR, + wrapS : WebGLConstants.REPEAT, + wrapT : WebGLConstants.REPEAT + } + ], + scenes : [ + { + nodes : [] + } + ], + shaders : [], + skins : [ + { + bindShapeMatrix : [ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ] + } + ], + techniques : [ + { + parameters: {}, + attributes: {}, + uniforms: {}, + states: { + enable: [] + } + } + ], + textures : [ + { + format: WebGLConstants.RGBA, + internalFormat: WebGLConstants.RGBA, + target: WebGLConstants.TEXTURE_2D, + type: WebGLConstants.UNSIGNED_BYTE + } + ], + extensionsUsed : [], + extensionsRequired : [] + }; + + function addDefaultsFromTemplate(object, template) { + for (var id in template) { + if (template.hasOwnProperty(id)) { + var templateValue = template[id]; + if (typeof templateValue === 'function') { + templateValue = templateValue(object); + } + if (defined(templateValue)) { + if (typeof templateValue === 'object') { + if (Array.isArray(templateValue)) { + var arrayValue = defaultValue(object[id], []); + if (templateValue.length > 0) { + var arrayTemplate = templateValue[0]; + if (typeof arrayTemplate === 'object') { + var arrayValueLength = arrayValue.length; + for (var i = 0; i < arrayValueLength; i++) { + addDefaultsFromTemplate(arrayValue[i], arrayTemplate); + } + } else { + arrayValue = defaultValue(object[id], templateValue); + } + } + object[id] = arrayValue; + } else { + var applyTemplate = templateValue['*']; + object[id] = defaultValue(object[id], {}); + var objectValue = object[id]; + if (defined(applyTemplate)) { + for (var subId in objectValue) { + if (objectValue.hasOwnProperty(subId) && subId !== 'extras') { + var subObject = objectValue[subId]; + addDefaultsFromTemplate(subObject, applyTemplate); + } + } + } else { + addDefaultsFromTemplate(objectValue, templateValue); + } + } + } else { + object[id] = defaultValue(object[id], templateValue); + } + } + } + } + } + + var defaultMaterial = { + values : { + emission : [ + 0.5, 0.5, 0.5, 1.0 + ] + } + }; + + var defaultTechnique = { + attributes : { + a_position : 'position' + }, + parameters : { + modelViewMatrix : { + semantic : 'MODELVIEW', + type : WebGLConstants.FLOAT_MAT4 + }, + projectionMatrix : { + semantic : 'PROJECTION', + type : WebGLConstants.FLOAT_MAT4 + }, + emission : { + type : WebGLConstants.FLOAT_VEC4, + value : [ + 0.5, 0.5, 0.5, 1.0 + ] + }, + position : { + semantic: 'POSITION', + type: WebGLConstants.FLOAT_VEC3 + } + }, + states : { + enable : [ + WebGLConstants.CULL_FACE, + WebGLConstants.DEPTH_TEST + ] + }, + uniforms : { + u_modelViewMatrix : 'modelViewMatrix', + u_projectionMatrix : 'projectionMatrix', + u_emission : 'emission' + } + }; + + var defaultProgram = { + attributes : [ + 'a_position' + ] + }; + + var defaultVertexShader = { + type : WebGLConstants.VERTEX_SHADER, + extras : { + _pipeline : { + extension : '.vert', + source : '' + + 'precision highp float;\n' + + '\n' + + 'uniform mat4 u_modelViewMatrix;\n' + + 'uniform mat4 u_projectionMatrix;\n' + + '\n' + + 'attribute vec3 a_position;\n' + + '\n' + + 'void main (void)\n' + + '{\n' + + ' gl_Position = u_projectionMatrix * u_modelViewMatrix * vec4(a_position, 1.0);\n' + + '}\n' + } + } + }; + + var defaultFragmentShader = { + type : WebGLConstants.FRAGMENT_SHADER, + extras : { + _pipeline : { + extension: '.frag', + source : '' + + 'precision highp float;\n' + + '\n' + + 'uniform vec4 u_emission;\n' + + '\n' + + 'void main(void)\n' + + '{\n' + + ' gl_FragColor = u_emission;\n' + + '}\n' + } + } + }; + + function addDefaultMaterial(gltf) { + var materials = gltf.materials; + var meshes = gltf.meshes; + + var defaultMaterialId; + + var meshesLength = meshes.length; + for (var meshId = 0; meshId < meshesLength; meshId++) { + var mesh = meshes[meshId]; + var primitives = mesh.primitives; + var primitivesLength = primitives.length; + for (var j = 0; j < primitivesLength; j++) { + var primitive = primitives[j]; + if (!defined(primitive.material)) { + if (!defined(defaultMaterialId)) { + defaultMaterialId = addToArray(materials, clone(defaultMaterial, true)); + } + primitive.material = defaultMaterialId; + } + } + } + } + + function addDefaultTechnique(gltf) { + var materials = gltf.materials; + var techniques = gltf.techniques; + var programs = gltf.programs; + var shaders = gltf.shaders; + + var defaultTechniqueId; + + var materialsLength = materials.length; + for (var materialId = 0; materialId < materialsLength; materialId++) { + var material = materials[materialId]; + var techniqueId = material.technique; + var extensions = defaultValue(material.extensions, {}); + var materialsCommon = extensions.KHR_materials_common; + if (!defined(techniqueId)) { + if (!defined(defaultTechniqueId) && !defined(materialsCommon)) { + var technique = clone(defaultTechnique, true); + defaultTechniqueId = addToArray(techniques, technique); + + var program = clone(defaultProgram, true); + technique.program = addToArray(programs, program); + + var vertexShader = clone(defaultVertexShader, true); + program.vertexShader = addToArray(shaders, vertexShader); + + var fragmentShader = clone(defaultFragmentShader, true); + program.fragmentShader = addToArray(shaders, fragmentShader); + } + material.technique = defaultTechniqueId; + } + + } + } + + function addDefaultByteOffsets(gltf) { + var accessors = gltf.accessors; + + var accessorLength = accessors.length; + for (var i = 0; i < accessorLength; i++) { + var accessor = accessors[i]; + if (!defined(accessor.byteOffset)) { + accessor.byteOffset = 0; + } + } + + var bufferViews = gltf.bufferViews; + + var bufferViewsLength = bufferViews.length; + for (var j = 0; j < bufferViewsLength; j++) { + var bufferView = bufferViews[j]; + if (!defined(bufferView.byteOffset)) { + bufferView.byteOffset = 0; + } + } + } + + function selectDefaultScene(gltf) { + var scenes = gltf.scenes; + + if (!defined(gltf.scene)) { + var scenesLength = scenes.length; + for (var sceneId = 0; sceneId < scenesLength; sceneId++) { + gltf.scene = sceneId; + break; + } + } + } + + function optimizeForCesium(gltf) { + // Give the diffuse uniform a semantic to support color replacement in 3D Tiles + var techniques = gltf.techniques; + var techniquesLength = techniques.length; + for (var techniqueId = 0; techniqueId < techniquesLength; techniqueId++) { + var technique = techniques[techniqueId]; + var parameters = technique.parameters; + if (defined(parameters.diffuse)) { + parameters.diffuse.semantic = '_3DTILESDIFFUSE'; + } + } + } + + function inferBufferViewTargets(gltf) { + // If bufferView elements are missing targets, we can infer their type from their use + var needsTarget = {}; + var shouldTraverse = 0; + ForEach.bufferView(gltf, function(bufferView, bufferViewId) { + if (!defined(bufferView.target)) { + needsTarget[bufferViewId] = true; + shouldTraverse++; + } + }); + if (shouldTraverse > 0) { + var accessors = gltf.accessors; + var bufferViews = gltf.bufferViews; + ForEach.mesh(gltf, function (mesh) { + ForEach.meshPrimitive(mesh, function (primitive) { + var indices = primitive.indices; + if (defined(indices)) { + var accessor = accessors[indices]; + var bufferViewId = accessor.bufferView; + if (needsTarget[bufferViewId]) { + var bufferView = bufferViews[bufferViewId]; + if (defined(bufferView)) { + bufferView.target = WebGLConstants.ELEMENT_ARRAY_BUFFER; + needsTarget[bufferViewId] = false; + shouldTraverse--; + } + } + } + ForEach.meshPrimitiveAttribute(primitive, function (accessorId) { + var accessor = accessors[accessorId]; + var bufferViewId = accessor.bufferView; + if (needsTarget[bufferViewId]) { + var bufferView = bufferViews[bufferViewId]; + if (defined(bufferView)) { + bufferView.target = WebGLConstants.ARRAY_BUFFER; + needsTarget[bufferViewId] = false; + shouldTraverse--; + } + } + }); + ForEach.meshPrimitiveTargetAttribute(primitive, function (targetAttribute) { + var bufferViewId = accessors[targetAttribute].bufferView; + if (needsTarget[bufferViewId]) { + var bufferView = bufferViews[bufferViewId]; + if (defined(bufferView)) { + bufferView.target = WebGLConstants.ARRAY_BUFFER; + needsTarget[bufferViewId] = false; + shouldTraverse--; + } + } + }); + }); + if (shouldTraverse === 0) { + return true; + } + }); + } + } + + /** + * Adds default glTF values if they don't exist. + * + * The glTF asset must be initialized for the pipeline. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {Object} [options] An object with the following properties: + * @param {Boolean} [options.optimizeForCesium] Optimize the defaults for Cesium. Uses the Cesium sun as the default light source. + * @returns {Object} The modified glTF. + * + * @see addPipelineExtras + * @see loadGltfUris + */ + function addDefaults(gltf, options) { + options = defaultValue(options, {}); + addDefaultsFromTemplate(gltf, gltfTemplate); + addDefaultMaterial(gltf); + addDefaultTechnique(gltf); + addDefaultByteOffsets(gltf); + selectDefaultScene(gltf); + inferBufferViewTargets(gltf); + if (options.optimizeForCesium) { + optimizeForCesium(gltf); + } + return gltf; + } + + return addDefaults; +}); diff --git a/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js b/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js new file mode 100644 index 000000000000..49ec2de50fa6 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js @@ -0,0 +1,28 @@ +define([ + './addExtensionsUsed', + '../../Core/defined' + ], function( + addExtensionsUsed, + defined) { + 'use strict'; + + /** + * Adds an extension to gltf.extensionsRequired if it does not already exist. + * Initializes extensionsRequired if it is not defined. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {String} extension The extension to add. + */ + function addExtensionsRequired(gltf, extension) { + var extensionsRequired = gltf.extensionsRequired; + if (!defined(extensionsRequired)) { + extensionsRequired = []; + gltf.extensionsRequired = extensionsRequired; + } + if (extensionsRequired.indexOf(extension) < 0) { + extensionsRequired.push(extension); + } + addExtensionsUsed(gltf, extension); + } + return addExtensionsRequired; +}); diff --git a/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js b/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js new file mode 100644 index 000000000000..6d8bed56db03 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js @@ -0,0 +1,25 @@ +define([ + '../../Core/defined' + ], function( + defined) { + 'use strict'; + + /** + * Adds an extension to gltf.extensionsUsed if it does not already exist. + * Initializes extensionsUsed if it is not defined. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {String} extension The extension to add. + */ + function addExtensionsUsed(gltf, extension) { + var extensionsUsed = gltf.extensionsUsed; + if (!defined(extensionsUsed)) { + extensionsUsed = []; + gltf.extensionsUsed = extensionsUsed; + } + if (extensionsUsed.indexOf(extension) < 0) { + extensionsUsed.push(extension); + } + } + return addExtensionsUsed; +}); diff --git a/Source/ThirdParty/GltfPipeline/addPipelineExtras.js b/Source/ThirdParty/GltfPipeline/addPipelineExtras.js new file mode 100644 index 000000000000..26770de6b816 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/addPipelineExtras.js @@ -0,0 +1,63 @@ +define([ + '../../Core/defaultValue', + '../../Core/defined' + ], function( + defaultValue, + defined) { + 'use strict'; + + // Objects with these ids should not have extras added + var exceptions = { + attributes: true, + uniforms: true, + extensions: true, + values: true, + samplers: true + }; + + /** + * Adds extras._pipeline to each object that can have extras in the glTF asset. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @returns {Object} The glTF asset with the added pipeline extras. + */ + function addPipelineExtras(gltf) { + var objectStack = []; + for (var rootArrayId in gltf) { + if (gltf.hasOwnProperty(rootArrayId)) { + var rootArray = gltf[rootArrayId]; + var rootArrayLength = rootArray.length; + for (var i = 0; i < rootArrayLength; i++) { + var rootObject = rootArray[i]; + if (defined(rootObject) && typeof rootObject === 'object') { + rootObject.extras = defaultValue(rootObject.extras, {}); + rootObject.extras._pipeline = defaultValue(rootObject.extras._pipeline, {}); + objectStack.push(rootObject); + } + } + } + } + while (objectStack.length > 0) { + var object = objectStack.pop(); + for (var propertyId in object) { + if (object.hasOwnProperty(propertyId)) { + var property = object[propertyId]; + if (defined(property) && typeof property === 'object' && propertyId !== 'extras') { + objectStack.push(property); + if (!exceptions[propertyId] && !Array.isArray(property)) { + property.extras = defaultValue(property.extras, {}); + property.extras._pipeline = defaultValue(property.extras._pipeline, {}); + } + } + } + } + } + gltf.extras = defaultValue(gltf.extras, {}); + gltf.extras._pipeline = defaultValue(gltf.extras._pipeline, {}); + gltf.asset = defaultValue(gltf.asset, {}); + gltf.asset.extras = defaultValue(gltf.asset.extras, {}); + gltf.asset.extras._pipeline = defaultValue(gltf.asset.extras._pipeline, {}); + return gltf; + } + return addPipelineExtras; +}); diff --git a/Source/ThirdParty/GltfPipeline/addToArray.js b/Source/ThirdParty/GltfPipeline/addToArray.js new file mode 100644 index 000000000000..8559cb54288b --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/addToArray.js @@ -0,0 +1,9 @@ +define([], function() { + 'use strict'; + + function addToArray(array, element) { + array.push(element); + return array.length - 1; + } + return addToArray; +}); diff --git a/Source/ThirdParty/GltfPipeline/byteLengthForComponentType.js b/Source/ThirdParty/GltfPipeline/byteLengthForComponentType.js new file mode 100644 index 000000000000..409bc740ad48 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/byteLengthForComponentType.js @@ -0,0 +1,34 @@ +define([ + '../../Core/WebGLConstants' + ], function( + WebGLConstants) { + 'use strict'; + + /** + * Utility function for retrieving the byte length of a component type. + * As per the spec: + * 5120 (BYTE) : 1 + * 5121 (UNSIGNED_BYTE) : 1 + * 5122 (SHORT) : 2 + * 5123 (UNSIGNED_SHORT) : 2 + * 5126 (FLOAT) : 4 + * 5125 (UNSIGNED_INT) : 4 + * + * @param {Number} [componentType] + * @returns {Number} The byte length of the component type. + */ + function byteLengthForComponentType(componentType) { + switch (componentType) { + case WebGLConstants.BYTE: + case WebGLConstants.UNSIGNED_BYTE: + return 1; + case WebGLConstants.SHORT: + case WebGLConstants.UNSIGNED_SHORT: + return 2; + case WebGLConstants.FLOAT: + case WebGLConstants.UNSIGNED_INT: + return 4; + } + } + return byteLengthForComponentType; +}); diff --git a/Source/ThirdParty/GltfPipeline/findAccessorMinMax.js b/Source/ThirdParty/GltfPipeline/findAccessorMinMax.js new file mode 100644 index 000000000000..3ebf53b24eb1 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/findAccessorMinMax.js @@ -0,0 +1,63 @@ +define([ + './getAccessorByteStride', + './numberOfComponentsForType', + '../../Core/arrayFill', + '../../Core/ComponentDatatype', + '../../Core/defined' + ], function( + getAccessorByteStride, + numberOfComponentsForType, + arrayFill, + ComponentDatatype, + defined) { + 'use strict'; + + /** + * Finds the min and max for an accessor in gltf. + * + * The glTF asset must be initialized for the pipeline. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {Object} accessor The accessor object from the glTF asset to read. + * @returns {{min: Array, max: Array}} min holding the array of minimum values and max holding the array of maximum values. + * + * @see addPipelineExtras + * @see loadGltfUris + */ + function findAccessorMinMax(gltf, accessor) { + var bufferViews = gltf.bufferViews; + var buffers = gltf.buffers; + var bufferViewId = accessor.bufferView; + var numberOfComponents = numberOfComponentsForType(accessor.type); + var min = arrayFill(new Array(numberOfComponents), Number.POSITIVE_INFINITY); + var max = arrayFill(new Array(numberOfComponents), Number.NEGATIVE_INFINITY); + if (defined(bufferViewId) && defined(bufferViews) && bufferViews.hasOwnProperty(bufferViewId)) { + var bufferView = bufferViews[bufferViewId]; + var bufferId = bufferView.buffer; + if (defined(bufferId) && defined(buffers) && buffers.hasOwnProperty(bufferId)) { + var buffer = buffers[bufferId]; + var source = buffer.extras._pipeline.source; + + var count = accessor.count; + var byteStride = getAccessorByteStride(gltf, accessor); + var byteOffset = accessor.byteOffset + bufferView.byteOffset; + var componentType = accessor.componentType; + + for (var i = 0; i < count; i++) { + var typedArray = ComponentDatatype.createArrayBufferView(componentType, source.buffer, byteOffset + source.byteOffset, numberOfComponents); + for (var j = 0; j < numberOfComponents; j++) { + var value = typedArray[j]; + min[j] = Math.min(min[j], value); + max[j] = Math.max(max[j], value); + } + byteOffset += byteStride; + } + } + } + return { + min : min, + max : max + }; + } + return findAccessorMinMax; +}); diff --git a/Source/ThirdParty/GltfPipeline/getAccessorByteStride.js b/Source/ThirdParty/GltfPipeline/getAccessorByteStride.js new file mode 100644 index 000000000000..c9dbfe0f9fb4 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/getAccessorByteStride.js @@ -0,0 +1,27 @@ +define([ + './byteLengthForComponentType', + './numberOfComponentsForType', + '../../Core/defined' + ], function( + byteLengthForComponentType, + numberOfComponentsForType, + defined) { + 'use strict'; + + /** + * Returns the byte stride of the provided accessor. + * If the byteStride is 0, it is calculated based on type and componentType + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {Object} accessor The accessor. + * @returns {Number} The byte stride of the accessor. + */ + function getAccessorByteStride(gltf, accessor) { + var bufferView = gltf.bufferViews[accessor.bufferView]; + if (defined(bufferView.byteStride) && bufferView.byteStride > 0) { + return bufferView.byteStride; + } + return byteLengthForComponentType(accessor.componentType) * numberOfComponentsForType(accessor.type); + } + return getAccessorByteStride; +}); diff --git a/Source/ThirdParty/GltfPipeline/getJointCountForMaterials.js b/Source/ThirdParty/GltfPipeline/getJointCountForMaterials.js new file mode 100644 index 000000000000..ba299be639e7 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/getJointCountForMaterials.js @@ -0,0 +1,44 @@ +define([ + './ForEach', + '../../Core/defined' + ], function( + ForEach, + defined) { + 'use strict'; + + function getJointCountForMaterials(gltf) { + var meshes = gltf.meshes; + var jointCountForMaterialId = {}; + + var nodesForSkinId = {}; + ForEach.node(gltf, function(node) { + if (defined(node.skin)) { + if (!defined(nodesForSkinId[node.skin])) { + nodesForSkinId[node.skin] = []; + } + nodesForSkinId[node.skin].push(node); + } + }); + + ForEach.skin(gltf, function(skin, skinId) { + var jointCount = skin.joints.length; + var meshPrimitiveFunction = function(primitive) { + jointCountForMaterialId[primitive.material] = jointCount; + }; + var skinnedNodes = nodesForSkinId[skinId]; + var skinnedNodesLength = skinnedNodes.length; + for (var i = 0; i < skinnedNodesLength; i++) { + var skinnedNode = skinnedNodes[i]; + var meshId = skinnedNode.mesh; + if (defined(meshId)) { + var mesh = meshes[meshId]; + ForEach.meshPrimitive(mesh, meshPrimitiveFunction); + } + } + }); + + return jointCountForMaterialId; + } + + return getJointCountForMaterials; +}); diff --git a/Source/ThirdParty/GltfPipeline/getUniqueId.js b/Source/ThirdParty/GltfPipeline/getUniqueId.js new file mode 100644 index 000000000000..59f7a36cdf5b --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/getUniqueId.js @@ -0,0 +1,31 @@ +define([ + '../../Core/defined' + ], function( + defined) { + 'use strict'; + + /** + * Given a prefix for a new ID, checks the glTF asset for matching prefixes in top-level objects with IDs and returns a unique ID. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {String} prefix The string to try to use as the id. + * @returns {String} A unique id beginning with prefix. + */ + function getUniqueId(gltf, prefix) { + var id = prefix; + var appendIndex = 0; + for (var topLevelGroupId in gltf) { + if (gltf.hasOwnProperty(topLevelGroupId)) { + var topLevelGroup = gltf[topLevelGroupId]; + var match = topLevelGroup[id]; + while (defined(match)) { + id = prefix + '_' + appendIndex; + match = topLevelGroup[id]; + appendIndex++; + } + } + } + return id; + } + return getUniqueId; +}); diff --git a/Source/ThirdParty/GltfPipeline/glslTypeToWebGLConstant.js b/Source/ThirdParty/GltfPipeline/glslTypeToWebGLConstant.js new file mode 100644 index 000000000000..f05c65a0c871 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/glslTypeToWebGLConstant.js @@ -0,0 +1,28 @@ +define([ + '../../Core/WebGLConstants' + ], function( + WebGLConstants) { + 'use strict'; + + function glslTypeToWebGLConstant(glslType) { + switch (glslType) { + case 'float': + return WebGLConstants.FLOAT; + case 'vec2': + return WebGLConstants.FLOAT_VEC2; + case 'vec3': + return WebGLConstants.FLOAT_VEC3; + case 'vec4': + return WebGLConstants.FLOAT_VEC4; + case 'mat2': + return WebGLConstants.FLOAT_MAT2; + case 'mat3': + return WebGLConstants.FLOAT_MAT3; + case 'mat4': + return WebGLConstants.FLOAT_MAT4; + case 'sampler2D': + return WebGLConstants.SAMPLER_2D; + } + } + return glslTypeToWebGLConstant; +}); diff --git a/Source/ThirdParty/GltfPipeline/numberOfComponentsForType.js b/Source/ThirdParty/GltfPipeline/numberOfComponentsForType.js new file mode 100644 index 000000000000..f87c62123c3b --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/numberOfComponentsForType.js @@ -0,0 +1,36 @@ +define([], function() { + 'use strict'; + + /** + * Utility function for retrieving the number of components in a given type. + * As per the spec: + * 'SCALAR' : 1 + * 'VEC2' : 2 + * 'VEC3' : 3 + * 'VEC4' : 4 + * 'MAT2' : 4 + * 'MAT3' : 9 + * 'MAT4' : 16 + * + * @param {String} type glTF type + * @returns {Number} The number of components in that type. + */ + function numberOfComponentsForType(type) { + switch (type) { + case 'SCALAR': + return 1; + case 'VEC2': + return 2; + case 'VEC3': + return 3; + case 'VEC4': + case 'MAT2': + return 4; + case 'MAT3': + return 9; + case 'MAT4': + return 16; + } + } + return numberOfComponentsForType; +}); diff --git a/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js b/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js new file mode 100644 index 000000000000..1fdc55138afb --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js @@ -0,0 +1,124 @@ +define([ + './addPipelineExtras', + './removeExtensionsUsed', + './updateVersion', + '../../Core/ComponentDatatype', + '../../Core/defined', + '../../Core/DeveloperError', + '../../Core/getMagic', + '../../Core/getStringFromTypedArray', + '../../Core/WebGLConstants' + ], function( + addPipelineExtras, + removeExtensionsUsed, + updateVersion, + ComponentDatatype, + defined, + DeveloperError, + getMagic, + getStringFromTypedArray, + WebGLConstants) { + 'use strict'; + + /** + * Parses a binary glTF buffer into glTF JSON. + * + * @param {Uint8Array} data The binary glTF data to parse. + * @returns {Object} The parsed binary glTF. + */ + function parseBinaryGltf(data) { + var headerView = ComponentDatatype.createArrayBufferView(WebGLConstants.INT, data.buffer, data.byteOffset, 5); + + // Check that the magic string is present + var magic = getMagic(data); + if (magic !== 'glTF') { + throw new DeveloperError('File is not valid binary glTF'); + } + + // Check that the version is 1 or 2 + var version = headerView[1]; + if (version !== 1 && version !== 2) { + throw new DeveloperError('Binary glTF version is not 1 or 2'); + } + + var gltf; + var buffers; + var length; + // Load binary glTF version 1 + if (version === 1) { + length = headerView[2]; + var contentLength = headerView[3]; + var contentFormat = headerView[4]; + + // Check that the content format is 0, indicating that it is JSON + if (contentFormat !== 0) { + throw new DeveloperError('Binary glTF scene format is not JSON'); + } + + var jsonStart = 20; + var binaryStart = jsonStart + contentLength; + + var contentString = getStringFromTypedArray(data, jsonStart, contentLength); + gltf = JSON.parse(contentString); + + // Clone just the binary chunk so the underlying buffer can be freed + var binaryData = new Uint8Array(data.subarray(binaryStart, length)); + + buffers = gltf.buffers; + if (defined(buffers) && Object.keys(buffers).length > 0) { + var binaryGltfBuffer = buffers.binary_glTF; + // In some older models, the binary glTF buffer is named KHR_binary_glTF + if (!defined(binaryGltfBuffer)) { + binaryGltfBuffer = buffers.KHR_binary_glTF; + } + if (defined(binaryGltfBuffer)) { + binaryGltfBuffer.extras = { + _pipeline: { + source: binaryData + } + }; + } + } + // Update to glTF 2.0 + updateVersion(gltf); + // Remove the KHR_binary_glTF extension + removeExtensionsUsed(gltf, 'KHR_binary_glTF'); + addPipelineExtras(gltf); + } + + // Load binary glTF version 2 + if (version === 2) { + length = headerView[2]; + var byteOffset = 12; + var binaryBuffer; + while (byteOffset < length) { + var chunkHeaderView = ComponentDatatype.createArrayBufferView(WebGLConstants.INT, data.buffer, data.byteOffset + byteOffset, 2); + var chunkLength = chunkHeaderView[0]; + var chunkType = chunkHeaderView[1]; + byteOffset += 8; + var chunkBuffer = data.subarray(byteOffset, byteOffset + chunkLength); + byteOffset += chunkLength; + // Load JSON chunk + if (chunkType === 0x4E4F534A) { + var jsonString = getStringFromTypedArray(chunkBuffer); + gltf = JSON.parse(jsonString); + addPipelineExtras(gltf); + } + // Load Binary chunk + else if (chunkType === 0x004E4942) { + // Clone just the binary chunk so the underlying buffer can be freed + binaryBuffer = new Uint8Array(chunkBuffer); + } + } + if (defined(gltf) && defined(binaryBuffer)) { + buffers = gltf.buffers; + if (defined(buffers) && buffers.length > 0) { + var buffer = buffers[0]; + buffer.extras._pipeline.source = binaryBuffer; + } + } + } + return gltf; + } + return parseBinaryGltf; +}); diff --git a/Source/Scene/modelMaterialsCommon.js b/Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js similarity index 61% rename from Source/Scene/modelMaterialsCommon.js rename to Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js index 08a004db888c..077430b9a32c 100644 --- a/Source/Scene/modelMaterialsCommon.js +++ b/Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js @@ -1,32 +1,115 @@ define([ - '../Core/defaultValue', - '../Core/defined', - '../Core/WebGLConstants' + './addToArray', + './ForEach', + './numberOfComponentsForType', + './techniqueParameterForSemantic', + './webGLConstantToGlslType', + './glslTypeToWebGLConstant', + '../../Core/clone', + '../../Core/defined', + '../../Core/defaultValue', + '../../Core/WebGLConstants' ], function( - defaultValue, + addToArray, + ForEach, + numberOfComponentsForType, + techniqueParameterForSemantic, + webGLConstantToGlslType, + glslTypeToWebGLConstant, + clone, defined, + defaultValue, WebGLConstants) { 'use strict'; - function webGLConstantToGlslType(webGLValue) { - switch(webGLValue) { - case WebGLConstants.FLOAT: - return 'float'; - case WebGLConstants.FLOAT_VEC2: - return 'vec2'; - case WebGLConstants.FLOAT_VEC3: - return 'vec3'; - case WebGLConstants.FLOAT_VEC4: - return 'vec4'; - case WebGLConstants.FLOAT_MAT2: - return 'mat2'; - case WebGLConstants.FLOAT_MAT3: - return 'mat3'; - case WebGLConstants.FLOAT_MAT4: - return 'mat4'; - case WebGLConstants.SAMPLER_2D: - return 'sampler2D'; + /** + * @private + */ + function processModelMaterialsCommon(gltf, options) { + options = defaultValue(options, {}); + + if (!defined(gltf)) { + return undefined; } + + var hasExtension = false; + var extensionsRequired = gltf.extensionsRequired; + var extensionsUsed = gltf.extensionsUsed; + if (defined(extensionsUsed)) { + var index = extensionsUsed.indexOf('KHR_materials_common'); + if (index >= 0) { + extensionsUsed.splice(index, 1); + hasExtension = true; + } + if (defined(extensionsRequired)) { + index = extensionsRequired.indexOf('KHR_materials_common'); + if (index >= 0) { + extensionsRequired.splice(index, 1); + } + } + } + + if (hasExtension) { + if (!defined(gltf.programs)) { + gltf.programs = []; + } + if (!defined(gltf.shaders)) { + gltf.shaders = []; + } + if (!defined(gltf.techniques)) { + gltf.techniques = []; + } + lightDefaults(gltf); + + var lightParameters = generateLightParameters(gltf); + + // Pre-processing to assign skinning info and address incompatibilities + splitIncompatibleSkins(gltf); + + var techniques = {}; + ForEach.material(gltf, function(material) { + if (defined(material.extensions) && defined(material.extensions.KHR_materials_common)) { + var khrMaterialsCommon = material.extensions.KHR_materials_common; + var techniqueKey = getTechniqueKey(khrMaterialsCommon); + var technique = techniques[techniqueKey]; + if (!defined(technique)) { + technique = generateTechnique(gltf, khrMaterialsCommon, lightParameters, options); + techniques[techniqueKey] = technique; + } + + // Take advantage of the fact that we generate techniques that use the + // same parameter names as the extension values. + material.values = {}; + var values = khrMaterialsCommon.values; + for (var valueName in values) { + if (values.hasOwnProperty(valueName)) { + var value = values[valueName]; + material.values[valueName] = value; + } + } + + material.technique = technique; + + delete material.extensions.KHR_materials_common; + if (Object.keys(material.extensions).length === 0) { + delete material.extensions; + } + } + }); + + if (defined(gltf.extensions)) { + delete gltf.extensions.KHR_materials_common; + if (Object.keys(gltf.extensions).length === 0) { + delete gltf.extensions; + } + } + + // If any primitives have semantics that aren't declared in the generated + // shaders, we want to preserve them. + ensureSemanticExistence(gltf); + } + + return gltf; } function generateLightParameters(gltf) { @@ -55,7 +138,7 @@ define([ // Add light parameters to result var lightCount = 0; - for(var lightName in lights) { + for (var lightName in lights) { if (lights.hasOwnProperty(lightName)) { var light = lights[lightName]; var lightType = light.type; @@ -65,7 +148,7 @@ define([ } var lightBaseName = 'light' + lightCount.toString(); light.baseName = lightBaseName; - switch(lightType) { + switch (lightType) { case 'ambient': var ambient = light.ambient; result[lightBaseName + 'Color'] = { @@ -75,14 +158,12 @@ define([ break; case 'directional': var directional = light.directional; - result[lightBaseName + 'Color'] = - { + result[lightBaseName + 'Color'] = { type: WebGLConstants.FLOAT_VEC3, value: directional.color }; if (defined(light.node)) { - result[lightBaseName + 'Transform'] = - { + result[lightBaseName + 'Transform'] = { node: light.node, semantic: 'MODELVIEW', type: WebGLConstants.FLOAT_MAT4 @@ -91,35 +172,30 @@ define([ break; case 'point': var point = light.point; - result[lightBaseName + 'Color'] = - { + result[lightBaseName + 'Color'] = { type: WebGLConstants.FLOAT_VEC3, value: point.color }; if (defined(light.node)) { - result[lightBaseName + 'Transform'] = - { + result[lightBaseName + 'Transform'] = { node: light.node, semantic: 'MODELVIEW', type: WebGLConstants.FLOAT_MAT4 }; } - result[lightBaseName + 'Attenuation'] = - { + result[lightBaseName + 'Attenuation'] = { type: WebGLConstants.FLOAT_VEC3, value: [point.constantAttenuation, point.linearAttenuation, point.quadraticAttenuation] }; break; case 'spot': var spot = light.spot; - result[lightBaseName + 'Color'] = - { + result[lightBaseName + 'Color'] = { type: WebGLConstants.FLOAT_VEC3, value: spot.color }; if (defined(light.node)) { - result[lightBaseName + 'Transform'] = - { + result[lightBaseName + 'Transform'] = { node: light.node, semantic: 'MODELVIEW', type: WebGLConstants.FLOAT_MAT4 @@ -131,14 +207,12 @@ define([ useInFragment: true }; } - result[lightBaseName + 'Attenuation'] = - { + result[lightBaseName + 'Attenuation'] = { type: WebGLConstants.FLOAT_VEC3, value: [spot.constantAttenuation, spot.linearAttenuation, spot.quadraticAttenuation] }; - result[lightBaseName + 'FallOff'] = - { + result[lightBaseName + 'FallOff'] = { type: WebGLConstants.FLOAT_VEC2, value: [spot.fallOffAngle, spot.fallOffExponent] }; @@ -152,21 +226,11 @@ define([ return result; } - function getNextId(dictionary, baseName, startingCount) { - var count = defaultValue(startingCount, 0); - var nextId; - do { - nextId = baseName + (count++).toString(); - } while(defined(dictionary[nextId])); - - return nextId; - } - - var techniqueCount = 0; - var vertexShaderCount = 0; - var fragmentShaderCount = 0; - var programCount = 0; function generateTechnique(gltf, khrMaterialsCommon, lightParameters, options) { + var optimizeForCesium = defaultValue(options.optimizeForCesium, false); + var hasCesiumRTCExtension = defined(gltf.extensions) && defined(gltf.extensions.CESIUM_RTC); + var addBatchIdToGeneratedShaders = defaultValue(options.addBatchIdToGeneratedShaders, false); + var techniques = gltf.techniques; var shaders = gltf.shaders; var programs = gltf.programs; @@ -175,26 +239,31 @@ define([ if (defined(gltf.extensions) && defined(gltf.extensions.KHR_materials_common)) { lights = gltf.extensions.KHR_materials_common.lights; } - var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0); - var hasSkinning = (jointCount > 0); var parameterValues = khrMaterialsCommon.values; + if (defined(khrMaterialsCommon.transparent)) { + parameterValues.transparent = khrMaterialsCommon.transparent; + } + if (defined(khrMaterialsCommon.doubleSided)) { + parameterValues.doubleSided = khrMaterialsCommon.doubleSided; + } + var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0); + + var hasSkinning = jointCount > 0; + var skinningInfo = {}; + if (hasSkinning) { + skinningInfo = khrMaterialsCommon.extras._pipeline.skinning; + } var vertexShader = 'precision highp float;\n'; var fragmentShader = 'precision highp float;\n'; - // Generate IDs for our new objects - var techniqueId = getNextId(techniques, 'technique', techniqueCount); - var vertexShaderId = getNextId(shaders, 'vertexShader', vertexShaderCount); - var fragmentShaderId = getNextId(shaders, 'fragmentShader', fragmentShaderCount); - var programId = getNextId(programs, 'program', programCount); - var hasNormals = (lightingModel !== 'CONSTANT'); // Add techniques var techniqueParameters = { // Add matrices modelViewMatrix: { - semantic: options.useCesiumRTCMatrixInShaders ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW', + semantic: hasCesiumRTCExtension ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW', type: WebGLConstants.FLOAT_MAT4 }, projectionMatrix: { @@ -221,7 +290,7 @@ define([ // Add material parameters var lowerCase; var hasTexCoords = false; - for(var name in parameterValues) { + for (var name in parameterValues) { //generate shader parameters for KHR_materials_common attributes //(including a check, because some boolean flags should not be used as shader parameters) if (parameterValues.hasOwnProperty(name) && (name !== 'transparent') && (name !== 'doubleSided')) { @@ -237,7 +306,7 @@ define([ } // Give the diffuse uniform a semantic to support color replacement in 3D Tiles - if (defined(techniqueParameters.diffuse)) { + if (defined(techniqueParameters.diffuse) && optimizeForCesium) { techniqueParameters.diffuse.semantic = '_3DTILESDIFFUSE'; } @@ -253,16 +322,15 @@ define([ // Generate uniforms object before attributes are added var techniqueUniforms = {}; for (var paramName in techniqueParameters) { - if (techniqueParameters.hasOwnProperty(paramName)) { + if (techniqueParameters.hasOwnProperty(paramName) && paramName !== 'extras') { var param = techniqueParameters[paramName]; techniqueUniforms['u_' + paramName] = paramName; - var arraySize = defined(param.count) ? '['+param.count+']' : ''; + var arraySize = defined(param.count) ? '[' + param.count + ']' : ''; if (((param.type !== WebGLConstants.FLOAT_MAT3) && (param.type !== WebGLConstants.FLOAT_MAT4)) || param.useInFragment) { fragmentShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n'; delete param.useInFragment; - } - else { + } else { vertexShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n'; } } @@ -271,10 +339,34 @@ define([ // Add attributes with semantics var vertexShaderMain = ''; if (hasSkinning) { - vertexShaderMain += ' mat4 skinMat = a_weight.x * u_jointMatrix[int(a_joint.x)];\n'; - vertexShaderMain += ' skinMat += a_weight.y * u_jointMatrix[int(a_joint.y)];\n'; - vertexShaderMain += ' skinMat += a_weight.z * u_jointMatrix[int(a_joint.z)];\n'; - vertexShaderMain += ' skinMat += a_weight.w * u_jointMatrix[int(a_joint.w)];\n'; + var i, j; + var numberOfComponents = numberOfComponentsForType(skinningInfo.type); + var matrix = false; + if (skinningInfo.type.indexOf('MAT') === 0) { + matrix = true; + numberOfComponents = Math.sqrt(numberOfComponents); + } + if (!matrix) { + for (i = 0; i < numberOfComponents; i++) { + if (i === 0) { + vertexShaderMain += ' mat4 skinMat = '; + } else { + vertexShaderMain += ' skinMat += '; + } + vertexShaderMain += 'a_weight[' + i + '] * u_jointMatrix[int(a_joint[' + i + '])];\n'; + } + } else { + for (i = 0; i < numberOfComponents; i++) { + for (j = 0; j < numberOfComponents; j++) { + if (i === 0 && j === 0) { + vertexShaderMain += ' mat4 skinMat = '; + } else { + vertexShaderMain += ' skinMat += '; + } + vertexShaderMain += 'a_weight[' + i + '][' + j + '] * u_jointMatrix[int(a_joint[' + i + '][' + j + '])];\n'; + } + } + } } // Add position always @@ -289,8 +381,7 @@ define([ vertexShader += 'varying vec3 v_positionEC;\n'; if (hasSkinning) { vertexShaderMain += ' vec4 pos = u_modelViewMatrix * skinMat * vec4(a_position,1.0);\n'; - } - else { + } else { vertexShaderMain += ' vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);\n'; } vertexShaderMain += ' v_positionEC = pos.xyz;\n'; @@ -308,8 +399,7 @@ define([ vertexShader += 'varying vec3 v_normal;\n'; if (hasSkinning) { vertexShaderMain += ' v_normal = u_normalMatrix * mat3(skinMat) * a_normal;\n'; - } - else { + } else { vertexShaderMain += ' v_normal = u_normalMatrix * a_normal;\n'; } @@ -335,21 +425,24 @@ define([ if (hasSkinning) { techniqueAttributes.a_joint = 'joint'; + var attributeType = getShaderVariable(skinningInfo.type); + var webGLConstant = glslTypeToWebGLConstant(attributeType); + techniqueParameters.joint = { semantic: 'JOINT', - type: WebGLConstants.FLOAT_VEC4 + type: webGLConstant }; techniqueAttributes.a_weight = 'weight'; techniqueParameters.weight = { semantic: 'WEIGHT', - type: WebGLConstants.FLOAT_VEC4 + type: webGLConstant }; - vertexShader += 'attribute vec4 a_joint;\n'; - vertexShader += 'attribute vec4 a_weight;\n'; + vertexShader += 'attribute ' + attributeType + ' a_joint;\n'; + vertexShader += 'attribute ' + attributeType + ' a_weight;\n'; } - if (options.addBatchIdToGeneratedShaders) { + if (addBatchIdToGeneratedShaders) { techniqueAttributes.a_batchId = 'batchId'; techniqueParameters.batchId = { semantic: '_BATCHID', @@ -359,7 +452,7 @@ define([ } var hasSpecular = hasNormals && ((lightingModel === 'BLINN') || (lightingModel === 'PHONG')) && - defined(techniqueParameters.specular) && defined(techniqueParameters.shininess); + defined(techniqueParameters.specular) && defined(techniqueParameters.shininess); // Generate lighting code blocks var hasNonAmbientLights = false; @@ -374,11 +467,10 @@ define([ var lightColorName = 'u_' + lightBaseName + 'Color'; var varyingDirectionName; var varyingPositionName; - if(lightType === 'ambient') { + if (lightType === 'ambient') { hasAmbientLights = true; fragmentLightingBlock += ' ambientLight += ' + lightColorName + ';\n'; - } - else if (hasNormals) { + } else if (hasNormals) { hasNonAmbientLights = true; varyingDirectionName = 'v_' + lightBaseName + 'Direction'; varyingPositionName = 'v_' + lightBaseName + 'Position'; @@ -404,8 +496,7 @@ define([ fragmentLightingBlock += ' float attenuation = 1.0 / (u_' + lightBaseName + 'Attenuation.x + '; fragmentLightingBlock += '(u_' + lightBaseName + 'Attenuation.y * range) + '; fragmentLightingBlock += '(u_' + lightBaseName + 'Attenuation.z * range * range));\n'; - } - else { + } else { fragmentLightingBlock += ' float attenuation = 1.0;\n'; } @@ -427,8 +518,7 @@ define([ if (lightingModel === 'BLINN') { fragmentLightingBlock += ' vec3 h = normalize(l + viewDir);\n'; fragmentLightingBlock += ' float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess)) * attenuation;\n'; - } - else { // PHONG + } else { // PHONG fragmentLightingBlock += ' vec3 reflectDir = reflect(-l, normal);\n'; fragmentLightingBlock += ' float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess)) * attenuation;\n'; } @@ -445,15 +535,18 @@ define([ } if (!hasNonAmbientLights && (lightingModel !== 'CONSTANT')) { - fragmentLightingBlock += ' vec3 l = normalize(czm_sunDirectionEC);\n'; + if (optimizeForCesium) { + fragmentLightingBlock += ' vec3 l = normalize(czm_sunDirectionEC);\n'; + } else { + fragmentLightingBlock += ' vec3 l = vec3(0.0, 0.0, 1.0);\n'; + } fragmentLightingBlock += ' diffuseLight += vec3(1.0, 1.0, 1.0) * max(dot(normal,l), 0.);\n'; if (hasSpecular) { if (lightingModel === 'BLINN') { fragmentLightingBlock += ' vec3 h = normalize(l + viewDir);\n'; fragmentLightingBlock += ' float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess));\n'; - } - else { // PHONG + } else { // PHONG fragmentLightingBlock += ' vec3 reflectDir = reflect(-l, normal);\n'; fragmentLightingBlock += ' float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess));\n'; } @@ -483,8 +576,7 @@ define([ if (defined(techniqueParameters.diffuse)) { if (techniqueParameters.diffuse.type === WebGLConstants.SAMPLER_2D) { fragmentShader += ' vec4 diffuse = texture2D(u_diffuse, ' + v_texcoord + ');\n'; - } - else { + } else { fragmentShader += ' vec4 diffuse = u_diffuse;\n'; } fragmentShader += ' vec3 diffuseLight = vec3(0.0, 0.0, 0.0);\n'; @@ -494,8 +586,7 @@ define([ if (hasSpecular) { if (techniqueParameters.specular.type === WebGLConstants.SAMPLER_2D) { fragmentShader += ' vec3 specular = texture2D(u_specular, ' + v_texcoord + ').rgb;\n'; - } - else { + } else { fragmentShader += ' vec3 specular = u_specular.rgb;\n'; } fragmentShader += ' vec3 specularLight = vec3(0.0, 0.0, 0.0);\n'; @@ -503,24 +594,22 @@ define([ } if (defined(techniqueParameters.transparency)) { - finalColorComputation = ' gl_FragColor = vec4(color * diffuse.a, diffuse.a * u_transparency);\n'; - } - else { + finalColorComputation = ' gl_FragColor = vec4(color * diffuse.a * u_transparency, diffuse.a * u_transparency);\n'; + } else { finalColorComputation = ' gl_FragColor = vec4(color * diffuse.a, diffuse.a);\n'; } - } - else if (defined(techniqueParameters.transparency)) { - finalColorComputation = ' gl_FragColor = vec4(color, u_transparency);\n'; - } - else { - finalColorComputation = ' gl_FragColor = vec4(color, 1.0);\n'; + } else { + if (defined(techniqueParameters.transparency)) { + finalColorComputation = ' gl_FragColor = vec4(color * u_transparency, u_transparency);\n'; + } else { + finalColorComputation = ' gl_FragColor = vec4(color, 1.0);\n'; + } } if (defined(techniqueParameters.emission)) { if (techniqueParameters.emission.type === WebGLConstants.SAMPLER_2D) { fragmentShader += ' vec3 emission = texture2D(u_emission, ' + v_texcoord + ').rgb;\n'; - } - else { + } else { fragmentShader += ' vec3 emission = u_emission.rgb;\n'; } colorCreationBlock += ' color += emission;\n'; @@ -530,12 +619,10 @@ define([ if (defined(techniqueParameters.ambient)) { if (techniqueParameters.ambient.type === WebGLConstants.SAMPLER_2D) { fragmentShader += ' vec3 ambient = texture2D(u_ambient, ' + v_texcoord + ').rgb;\n'; - } - else { + } else { fragmentShader += ' vec3 ambient = u_ambient.rgb;\n'; } - } - else { + } else { fragmentShader += ' vec3 ambient = diffuse.rgb;\n'; } colorCreationBlock += ' color += ambient * ambientLight;\n'; @@ -551,14 +638,14 @@ define([ fragmentShader += '}\n'; var techniqueStates; - if (khrMaterialsCommon.transparent) { + if (parameterValues.transparent) { techniqueStates = { enable: [ WebGLConstants.DEPTH_TEST, WebGLConstants.BLEND ], - depthMask: false, functions: { + depthMask : [false], blendEquationSeparate: [ WebGLConstants.FUNC_ADD, WebGLConstants.FUNC_ADD @@ -571,15 +658,13 @@ define([ ] } }; - } - else if (khrMaterialsCommon.doubleSided) { + } else if (khrMaterialsCommon.doubleSided) { techniqueStates = { enable: [ WebGLConstants.DEPTH_TEST ] }; - } - else { // Not transparent or double sided + } else { // Not transparent or double sided techniqueStates = { enable: [ WebGLConstants.CULL_FACE, @@ -587,62 +672,69 @@ define([ ] }; } - techniques[techniqueId] = { - attributes: techniqueAttributes, - parameters: techniqueParameters, - program: programId, - states: techniqueStates, - uniforms: techniqueUniforms - }; // Add shaders - shaders[vertexShaderId] = { + var vertexShaderId = addToArray(shaders, { type: WebGLConstants.VERTEX_SHADER, - uri: '', - extras: { - source: vertexShader + extras: { + _pipeline: { + source: vertexShader, + extension: '.glsl' + } } - }; - shaders[fragmentShaderId] = { + }); + + var fragmentShaderId = addToArray(shaders, { type: WebGLConstants.FRAGMENT_SHADER, - uri: '', extras: { - source: fragmentShader + _pipeline: { + source: fragmentShader, + extension: '.glsl' + } } - }; + }); // Add program var programAttributes = Object.keys(techniqueAttributes); - programs[programId] = { + var programId = addToArray(programs, { attributes: programAttributes, fragmentShader: fragmentShaderId, vertexShader: vertexShaderId - }; + }); + + var techniqueId = addToArray(techniques, { + attributes: techniqueAttributes, + parameters: techniqueParameters, + program: programId, + states: techniqueStates, + uniforms: techniqueUniforms + }); return techniqueId; } - function getKHRMaterialsCommonValueType(paramName, paramValue) - { + function getKHRMaterialsCommonValueType(paramName, paramValue) { var value; // Backwards compatibility for COLLADA2GLTF v1.0-draft when it encoding // materials using KHR_materials_common with explicit type/value members if (defined(paramValue.value)) { value = paramValue.value; + } else if (defined(paramValue.index)) { + value = [paramValue.index]; } else { value = paramValue; } - switch (paramName) { + switch (paramName) { case 'ambient': - return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; + return value.length === 1 ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; case 'diffuse': - return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; + return value.length === 1 ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; case 'emission': - return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; + return value.length === 1 ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; case 'specular': - return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; + return value.length === 1 ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; case 'shininess': return WebGLConstants.FLOAT; case 'transparency': @@ -664,116 +756,193 @@ define([ var values = khrMaterialsCommon.values; var keys = Object.keys(values).sort(); var keysCount = keys.length; - for (var i=0;i 0) { + var skinningInfo = khrMaterialsCommon.extras._pipeline.skinning; + techniqueKey += skinningInfo.type + ';'; + } return techniqueKey; } - /** - * Modifies gltf in place. - * - * @private - */ - function modelMaterialsCommon(gltf, options) { - if (!defined(gltf)) { - return undefined; + function lightDefaults(gltf) { + if (!defined(gltf.extensions)) { + gltf.extensions = {}; } + var extensions = gltf.extensions; - options = defaultValue(options, defaultValue.EMPTY_OBJECT); - - var hasExtension = false; - var extensionsUsed = gltf.extensionsUsed; - if (defined(extensionsUsed)) { - var extensionsUsedCount = extensionsUsed.length; - for(var i=0;i= 0) || additional.indexOf('Factor') >= 0) || additional === 'doubleSided') { + parameterValues[additional] = material[additional]; + } + } + + var vertexShader = 'precision highp float;\n'; + var fragmentShader = 'precision highp float;\n'; + + var skin; + if (defined(gltf.skins)) { + skin = gltf.skins[0]; + } + var joints = (defined(skin)) ? skin.joints : []; + var jointCount = joints.length; + var skinningInfo = material.extras._pipeline.skinning; + var hasSkinning = defined(skinningInfo.type); + + var hasNormals = true; + var hasTangents = false; + var hasMorphTargets = false; + var morphTargets; + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + var targets = primitive.targets; + if (!hasMorphTargets && defined(targets)) { + hasMorphTargets = true; + morphTargets = targets; + } + var attributes = primitive.attributes; + for (var attribute in attributes) { + if (attribute.indexOf('TANGENT') >= 0) { + hasTangents = true; + } + } + }); + }); + + // Add techniques + var techniqueParameters = { + // Add matrices + modelViewMatrix : { + semantic : hasCesiumRTCExtension ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW', + type : WebGLConstants.FLOAT_MAT4 + }, + projectionMatrix : { + semantic : 'PROJECTION', + type : WebGLConstants.FLOAT_MAT4 + } + }; + + if (hasNormals) { + techniqueParameters.normalMatrix = { + semantic : 'MODELVIEWINVERSETRANSPOSE', + type : WebGLConstants.FLOAT_MAT3 + }; + } + + if (hasSkinning) { + techniqueParameters.jointMatrix = { + count : jointCount, + semantic : 'JOINTMATRIX', + type : WebGLConstants.FLOAT_MAT4 + }; + } + + if (hasMorphTargets) { + techniqueParameters.morphWeights = { + count : morphTargets.length, + semantic : 'MORPHWEIGHTS', + type : WebGLConstants.FLOAT + }; + } + + // Add material parameters + var hasTexCoords = false; + for (var name in parameterValues) { + //generate shader parameters + if (parameterValues.hasOwnProperty(name)) { + var valType = getPBRValueType(name, parameterValues[name]); + if (!hasTexCoords && (valType === WebGLConstants.SAMPLER_2D)) { + hasTexCoords = true; + } + techniqueParameters[name] = { + type : valType + }; + } + } + + // Generate uniforms object before attributes are added + var techniqueUniforms = {}; + for (var paramName in techniqueParameters) { + if (techniqueParameters.hasOwnProperty(paramName) && paramName !== 'extras') { + var param = techniqueParameters[paramName]; + techniqueUniforms['u_' + paramName] = paramName; + var arraySize = defined(param.count) ? '[' + param.count + ']' : ''; + if (((param.type !== WebGLConstants.FLOAT_MAT3) && (param.type !== WebGLConstants.FLOAT_MAT4) && (paramName !== 'morphWeights')) || + param.useInFragment) { + fragmentShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n'; + delete param.useInFragment; + } else { + vertexShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n'; + } + } + } + + // Add attributes with semantics + var vertexShaderMain = ''; + if (hasSkinning) { + var i, j; + var numberOfComponents = numberOfComponentsForType(skinningInfo.type); + var matrix = false; + if (skinningInfo.type.indexOf('MAT') === 0) { + matrix = true; + numberOfComponents = Math.sqrt(numberOfComponents); + } + if (!matrix) { + for (i = 0; i < numberOfComponents; i++) { + if (i === 0) { + vertexShaderMain += ' mat4 skinMatrix = '; + } else { + vertexShaderMain += ' skinMatrix += '; + } + vertexShaderMain += 'a_weight[' + i + '] * u_jointMatrix[int(a_joint[' + i + '])];\n'; + } + } else { + for (i = 0; i < numberOfComponents; i++) { + for (j = 0; j < numberOfComponents; j++) { + if (i === 0 && j === 0) { + vertexShaderMain += ' mat4 skinMatrix = '; + } else { + vertexShaderMain += ' skinMatrix += '; + } + vertexShaderMain += 'a_weight[' + i + '][' + j + '] * u_jointMatrix[int(a_joint[' + i + '][' + j + '])];\n'; + } + } + } + } + + // Add position always + var techniqueAttributes = { + a_position : 'position' + }; + techniqueParameters.position = { + semantic : 'POSITION', + type : WebGLConstants.FLOAT_VEC3 + }; + vertexShader += 'attribute vec3 a_position;\n'; + vertexShader += 'varying vec3 v_positionEC;\n'; + if (optimizeForCesium) { + vertexShader += 'varying vec3 v_positionWC;\n'; + } + + // Morph Target Weighting + vertexShaderMain += ' vec3 weightedPosition = a_position;\n'; + if (hasNormals) { + vertexShaderMain += ' vec3 weightedNormal = a_normal;\n'; + } + if (hasTangents) { + vertexShaderMain += ' vec3 weightedTangent = a_tangent;\n'; + } + if (hasMorphTargets) { + for (var k = 0; k < morphTargets.length; k++) { + var targetAttributes = morphTargets[k]; + for (var targetAttribute in targetAttributes) { + if (targetAttributes.hasOwnProperty(targetAttribute) && targetAttribute !== 'extras') { + var attributeLower = targetAttribute.toLowerCase() + '_' + k; + techniqueAttributes['a_' + attributeLower] = attributeLower; + techniqueParameters[attributeLower] = { + semantic : targetAttribute + '_' + k, + type : WebGLConstants.FLOAT_VEC3 + }; + vertexShader += 'attribute vec3 a_' + attributeLower + ';\n'; + if (targetAttribute === 'POSITION') { + vertexShaderMain += ' weightedPosition += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n'; + } else if (targetAttribute === 'NORMAL') { + vertexShaderMain += ' weightedNormal += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n'; + } else if (targetAttribute === 'TANGENT') { + vertexShaderMain += ' weightedTangent += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n'; + } + } + } + } + } + + // Final position computation + if (hasSkinning) { + vertexShaderMain += ' vec4 position = skinMatrix * vec4(weightedPosition, 1.0);\n'; + } else { + vertexShaderMain += ' vec4 position = vec4(weightedPosition, 1.0);\n'; + } + if (optimizeForCesium) { + vertexShaderMain += ' v_positionWC = (czm_model * position).xyz;\n'; + } + vertexShaderMain += ' position = u_modelViewMatrix * position;\n'; + vertexShaderMain += ' v_positionEC = position.xyz;\n'; + vertexShaderMain += ' gl_Position = u_projectionMatrix * position;\n'; + fragmentShader += 'varying vec3 v_positionEC;\n'; + if (optimizeForCesium) { + fragmentShader += 'varying vec3 v_positionWC;\n'; + } + + // Final normal computation + if (hasNormals) { + techniqueAttributes.a_normal = 'normal'; + techniqueParameters.normal = { + semantic : 'NORMAL', + type : WebGLConstants.FLOAT_VEC3 + }; + vertexShader += 'attribute vec3 a_normal;\n'; + vertexShader += 'varying vec3 v_normal;\n'; + if (hasSkinning) { + vertexShaderMain += ' v_normal = u_normalMatrix * mat3(skinMatrix) * weightedNormal;\n'; + } else { + vertexShaderMain += ' v_normal = u_normalMatrix * weightedNormal;\n'; + } + + fragmentShader += 'varying vec3 v_normal;\n'; + } + + // Read tangents if available + if (hasTangents) { + techniqueAttributes.a_tangent = 'tangent'; + techniqueParameters.tangent = { + semantic : 'TANGENT', + type : WebGLConstants.FLOAT_VEC3 + }; + vertexShader += 'attribute vec3 a_tangent;\n'; + vertexShader += 'varying vec3 v_tangent;\n'; + vertexShaderMain += ' v_tangent = (u_modelViewMatrix * vec4(weightedTangent, 1.0)).xyz;\n'; + + fragmentShader += 'varying vec3 v_tangent;\n'; + } + + // Add texture coordinates if the material uses them + var v_texcoord; + if (hasTexCoords) { + techniqueAttributes.a_texcoord_0 = 'texcoord_0'; + techniqueParameters.texcoord_0 = { + semantic : 'TEXCOORD_0', + type : WebGLConstants.FLOAT_VEC2 + }; + + v_texcoord = 'v_texcoord_0'; + vertexShader += 'attribute vec2 a_texcoord_0;\n'; + vertexShader += 'varying vec2 ' + v_texcoord + ';\n'; + vertexShaderMain += ' ' + v_texcoord + ' = a_texcoord_0;\n'; + + fragmentShader += 'varying vec2 ' + v_texcoord + ';\n'; + } + + // Add skinning information if available + if (hasSkinning) { + techniqueAttributes.a_joint = 'joint'; + var attributeType = getShaderVariable(skinningInfo.type); + var webGLConstant = glslTypeToWebGLConstant(attributeType); + + techniqueParameters.joint = { + semantic : 'JOINTS_0', + type : webGLConstant + }; + techniqueAttributes.a_weight = 'weight'; + techniqueParameters.weight = { + semantic : 'WEIGHTS_0', + type : webGLConstant + }; + + vertexShader += 'attribute ' + attributeType + ' a_joint;\n'; + vertexShader += 'attribute ' + attributeType + ' a_weight;\n'; + } + + if (addBatchIdToGeneratedShaders) { + techniqueAttributes.a_batchId = 'batchId'; + techniqueParameters.batchId = { + semantic: '_BATCHID', + type: WebGLConstants.FLOAT + }; + vertexShader += 'attribute float a_batchId;\n'; + } + + vertexShader += 'void main(void) \n{\n'; + vertexShader += vertexShaderMain; + vertexShader += '}\n'; + + // Fragment shader lighting + fragmentShader += 'const float M_PI = 3.141592653589793;\n'; + + fragmentShader += 'vec3 lambertianDiffuse(vec3 baseColor) \n' + + '{\n' + + ' return baseColor / M_PI;\n' + + '}\n\n'; + + fragmentShader += 'vec3 fresnelSchlick2(vec3 f0, vec3 f90, float VdotH) \n' + + '{\n' + + ' return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);\n' + + '}\n\n'; + + fragmentShader += 'vec3 fresnelSchlick(float metalness, float VdotH) \n' + + '{\n' + + ' return metalness + (vec3(1.0) - metalness) * pow(1.0 - VdotH, 5.0);\n' + + '}\n\n'; + + fragmentShader += 'float smithVisibilityG1(float NdotV, float roughness) \n' + + '{\n' + + ' float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n' + + ' return NdotV / (NdotV * (1.0 - k) + k);\n' + + '}\n\n'; + + fragmentShader += 'float smithVisibilityGGX(float roughness, float NdotL, float NdotV) \n' + + '{\n' + + ' return smithVisibilityG1(NdotL, roughness) * smithVisibilityG1(NdotV, roughness);\n' + + '}\n\n'; + + fragmentShader += 'float GGX(float roughness, float NdotH) \n' + + '{\n' + + ' float roughnessSquared = roughness * roughness;\n' + + ' float f = (NdotH * roughnessSquared - NdotH) * NdotH + 1.0;\n' + + ' return roughnessSquared / (M_PI * f * f);\n' + + '}\n\n'; + + fragmentShader += 'void main(void) \n{\n'; + + // Add normal mapping to fragment shader + if (hasNormals) { + fragmentShader += ' vec3 ng = normalize(v_normal);\n'; + if (defined(parameterValues.normalTexture)) { + if (hasTangents) { + // Read tangents from varying + fragmentShader += ' vec3 t = normalize(v_tangent);\n'; + fragmentShader += ' vec3 b = normalize(cross(ng, t));\n'; + fragmentShader += ' mat3 tbn = mat3(t, b, ng);\n'; + fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + v_texcoord + ').rgb;\n'; + fragmentShader += ' n = normalize(tbn * (2.0 * n - 1.0));\n'; + } else { + // Add standard derivatives extension + fragmentShader = '#ifdef GL_OES_standard_derivatives\n' + + '#extension GL_OES_standard_derivatives : enable\n' + + '#endif\n' + + fragmentShader; + // Compute tangents + fragmentShader += '#ifdef GL_OES_standard_derivatives\n'; + fragmentShader += ' vec3 pos_dx = dFdx(v_positionEC);\n'; + fragmentShader += ' vec3 pos_dy = dFdy(v_positionEC);\n'; + fragmentShader += ' vec3 tex_dx = dFdx(vec3(' + v_texcoord + ',0.0));\n'; + fragmentShader += ' vec3 tex_dy = dFdy(vec3(' + v_texcoord + ',0.0));\n'; + fragmentShader += ' vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);\n'; + fragmentShader += ' t = normalize(t - ng * dot(ng, t));\n'; + fragmentShader += ' vec3 b = normalize(cross(ng, t));\n'; + fragmentShader += ' mat3 tbn = mat3(t, b, ng);\n'; + fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + v_texcoord + ').rgb;\n'; + fragmentShader += ' n = normalize(tbn * (2.0 * n - 1.0));\n'; + fragmentShader += '#else\n'; + fragmentShader += ' vec3 n = ng;\n'; + fragmentShader += '#endif\n'; + } + } else { + fragmentShader += ' vec3 n = ng;\n'; + } + if (parameterValues.doubleSided) { + fragmentShader += ' if (!gl_FrontFacing)\n'; + fragmentShader += ' {\n'; + fragmentShader += ' n = -n;\n'; + fragmentShader += ' }\n'; + } + } + + // Add base color to fragment shader + if (defined(parameterValues.baseColorTexture)) { + fragmentShader += ' vec4 baseColorWithAlpha = texture2D(u_baseColorTexture, ' + v_texcoord + ');\n'; + if (defined(parameterValues.baseColorFactor)) { + fragmentShader += ' baseColorWithAlpha *= u_baseColorFactor;\n'; + } + } else { + if (defined(parameterValues.baseColorFactor)) { + fragmentShader += ' vec4 baseColorWithAlpha = u_baseColorFactor;\n'; + } else { + fragmentShader += ' vec4 baseColorWithAlpha = vec4(1.0);\n'; + } + } + fragmentShader += ' vec3 baseColor = baseColorWithAlpha.rgb;\n'; + // Add metallic-roughness to fragment shader + if (defined(parameterValues.metallicRoughnessTexture)) { + fragmentShader += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + v_texcoord + ').rgb;\n'; + fragmentShader += ' float metalness = clamp(metallicRoughness.b, 0.0, 1.0);\n'; + fragmentShader += ' float roughness = clamp(metallicRoughness.g, 0.04, 1.0);\n'; + if (defined(parameterValues.metallicFactor)) { + fragmentShader += ' metalness *= u_metallicFactor;\n'; + } + if (defined(parameterValues.roughnessFactor)) { + fragmentShader += ' roughness *= u_roughnessFactor;\n'; + } + } else { + if (defined(parameterValues.metallicFactor)) { + fragmentShader += ' float metalness = clamp(u_metallicFactor, 0.0, 1.0);\n'; + } else { + fragmentShader += ' float metalness = 1.0;\n'; + } + if (defined(parameterValues.roughnessFactor)) { + fragmentShader += ' float roughness = clamp(u_roughnessFactor, 0.04, 1.0);\n'; + } else { + fragmentShader += ' float roughness = 1.0;\n'; + } + } + fragmentShader += ' vec3 v = -normalize(v_positionEC);\n'; + + // Generate fragment shader's lighting block + fragmentShader += ' vec3 lightColor = vec3(1.0, 1.0, 1.0);\n'; + if (optimizeForCesium) { + fragmentShader += ' vec3 l = normalize(czm_sunDirectionEC);\n'; + } else { + fragmentShader += ' vec3 l = vec3(0.0, 0.0, 1.0);\n'; + } + fragmentShader += ' vec3 h = normalize(v + l);\n'; + if (optimizeForCesium) { + fragmentShader += ' vec3 r = normalize(czm_inverseViewRotation * normalize(reflect(v, n)));\n'; + // Figure out if the reflection vector hits the ellipsoid + fragmentShader += ' czm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC();\n'; + fragmentShader += ' float vertexRadius = length(v_positionWC);\n'; + fragmentShader += ' float horizonDotNadir = 1.0 - ellipsoid.radii.x / vertexRadius;\n'; + fragmentShader += ' float reflectionDotNadir = dot(r, normalize(v_positionWC));\n'; + // Flipping the X vector is a cheap way to get the inverse of czm_temeToPseudoFixed, since that's a rotation about Z. + fragmentShader += ' r.x = -r.x;\n'; + fragmentShader += ' r = -normalize(czm_temeToPseudoFixed * r);\n'; + fragmentShader += ' r.x = -r.x;\n'; + } else { + fragmentShader += ' vec3 r = normalize(reflect(v, n));\n'; + } + fragmentShader += ' float NdotL = clamp(dot(n, l), 0.001, 1.0);\n'; + fragmentShader += ' float NdotV = abs(dot(n, v)) + 0.001;\n'; + fragmentShader += ' float NdotH = clamp(dot(n, h), 0.0, 1.0);\n'; + fragmentShader += ' float LdotH = clamp(dot(l, h), 0.0, 1.0);\n'; + fragmentShader += ' float VdotH = clamp(dot(v, h), 0.0, 1.0);\n'; + + fragmentShader += ' vec3 f0 = vec3(0.04);\n'; + fragmentShader += ' float alpha = roughness * roughness;\n'; + fragmentShader += ' vec3 diffuseColor = baseColor * (1.0 - metalness);\n'; + fragmentShader += ' vec3 specularColor = mix(f0, baseColor, metalness);\n'; + fragmentShader += ' float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n'; + fragmentShader += ' vec3 r90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0));\n'; + fragmentShader += ' vec3 r0 = specularColor.rgb;\n'; + + fragmentShader += ' vec3 F = fresnelSchlick2(r0, r90, VdotH);\n'; + fragmentShader += ' float G = smithVisibilityGGX(alpha, NdotL, NdotV);\n'; + fragmentShader += ' float D = GGX(alpha, NdotH);\n'; + + fragmentShader += ' vec3 diffuseContribution = (1.0 - F) * lambertianDiffuse(baseColor);\n'; + fragmentShader += ' vec3 specularContribution = F * G * D / (4.0 * NdotL * NdotV);\n'; + fragmentShader += ' vec3 color = NdotL * lightColor * (diffuseContribution + specularContribution);\n'; + + if (optimizeForCesium) { + fragmentShader += ' float inverseRoughness = 1.0 - roughness;\n'; + fragmentShader += ' inverseRoughness *= inverseRoughness;\n'; + fragmentShader += ' vec3 sceneSkyBox = textureCube(czm_environmentMap, r).rgb * inverseRoughness;\n'; + + fragmentShader += ' float atmosphereHeight = 0.05;\n'; + fragmentShader += ' float blendRegionSize = 0.1 * ((1.0 - inverseRoughness) * 8.0 + 1.1 - horizonDotNadir);\n'; + fragmentShader += ' float farAboveHorizon = clamp(horizonDotNadir - blendRegionSize * 0.5, 1.0e-10 - blendRegionSize, 0.99999);\n'; + fragmentShader += ' float aroundHorizon = clamp(horizonDotNadir + blendRegionSize * 0.5, 1.0e-10 - blendRegionSize, 0.99999);\n'; + fragmentShader += ' float farBelowHorizon = clamp(horizonDotNadir + blendRegionSize * 1.5, 1.0e-10 - blendRegionSize, 0.99999);\n'; + fragmentShader += ' float smoothstepHeight = smoothstep(0.0, atmosphereHeight, horizonDotNadir);\n'; + fragmentShader += ' float lightScale = smoothstepHeight * 1.5 + 1.0;\n'; + + fragmentShader += ' vec3 diffuseIrradiance = mix(vec3(0.5), vec3(0.05), smoothstepHeight);\n'; + fragmentShader += ' vec3 belowHorizonColor = mix(vec3(0.1, 0.2, 0.4), vec3(0.2, 0.5, 0.7), smoothstepHeight);\n'; + fragmentShader += ' vec3 nadirColor = belowHorizonColor * 0.5;\n'; + fragmentShader += ' vec3 aboveHorizonColor = vec3(0.8, 0.9, 0.95);\n'; + fragmentShader += ' vec3 blueSkyColor = mix(vec3(0.09, 0.13, 0.24), aboveHorizonColor, reflectionDotNadir * inverseRoughness * 0.5 + 0.5);\n'; + fragmentShader += ' vec3 zenithColor = mix(blueSkyColor, sceneSkyBox, smoothstepHeight);\n'; + + fragmentShader += ' vec3 specularIrradiance = mix(zenithColor, aboveHorizonColor, smoothstep(farAboveHorizon, aroundHorizon, reflectionDotNadir) * inverseRoughness);\n'; + fragmentShader += ' specularIrradiance = mix(specularIrradiance, belowHorizonColor, smoothstep(aroundHorizon, farBelowHorizon, reflectionDotNadir) * inverseRoughness);\n'; + fragmentShader += ' specularIrradiance = mix(specularIrradiance, nadirColor, smoothstep(farBelowHorizon, 1.0, reflectionDotNadir) * inverseRoughness);\n'; + + fragmentShader += ' vec2 brdfLut = texture2D(czm_brdfLut, vec2(NdotV, 1.0 - roughness)).rg;\n'; + fragmentShader += ' vec3 IBLColor = (diffuseIrradiance * diffuseColor) + (specularIrradiance * (specularColor * brdfLut.x + brdfLut.y));\n'; + fragmentShader += ' color = color * lightScale + IBLColor;\n'; + } + + if (defined(parameterValues.occlusionTexture)) { + fragmentShader += ' color *= texture2D(u_occlusionTexture, ' + v_texcoord + ').r;\n'; + } + if (defined(parameterValues.emissiveTexture)) { + fragmentShader += ' vec3 emissive = texture2D(u_emissiveTexture, ' + v_texcoord + ').rgb;\n'; + if (defined(parameterValues.emissiveFactor)) { + fragmentShader += ' emissive *= u_emissiveFactor;\n'; + } + fragmentShader += ' color += emissive;\n'; + } + else { + if (defined(parameterValues.emissiveFactor)) { + fragmentShader += ' color += u_emissiveFactor;\n'; + } + } + + // Final color + var alphaMode = material.alphaMode; + if (defined(alphaMode)) { + if (alphaMode === 'MASK') { + var alphaCutoff = material.alphaCutoff; + if (defined(alphaCutoff)) { + fragmentShader += ' gl_FragColor = vec4(color, int(baseColorWithAlpha.a >= ' + alphaCutoff + '));\n'; + } else { + fragmentShader += ' gl_FragColor = vec4(color, 1.0);\n'; + } + } else if (alphaMode === 'BLEND') { + fragmentShader += ' gl_FragColor = vec4(color, baseColorWithAlpha.a);\n'; + } else { + fragmentShader += ' gl_FragColor = vec4(color, 1.0);\n'; + } + } else { + fragmentShader += ' gl_FragColor = vec4(color, 1.0);\n'; + } + fragmentShader += '}\n'; + + var techniqueStates; + if (defined(alphaMode) && alphaMode !== 'OPAQUE') { + techniqueStates = { + enable: [ + WebGLConstants.DEPTH_TEST, + WebGLConstants.BLEND + ], + functions: { + depthMask : [false], + blendEquationSeparate: [ + WebGLConstants.FUNC_ADD, + WebGLConstants.FUNC_ADD + ], + blendFuncSeparate: [ + WebGLConstants.ONE, + WebGLConstants.ONE_MINUS_SRC_ALPHA, + WebGLConstants.ONE, + WebGLConstants.ONE_MINUS_SRC_ALPHA + ] + } + }; + } else if (parameterValues.doubleSided) { + techniqueStates = { + enable : [ + WebGLConstants.DEPTH_TEST + ] + }; + } else { + techniqueStates = { + enable : [ + WebGLConstants.CULL_FACE, + WebGLConstants.DEPTH_TEST + ] + }; + } + + // Add shaders + var vertexShaderId = addToArray(shaders, { + type : WebGLConstants.VERTEX_SHADER, + extras : { + _pipeline : { + source : vertexShader, + extension : '.glsl' + } + } + }); + + var fragmentShaderId = addToArray(shaders, { + type : WebGLConstants.FRAGMENT_SHADER, + extras : { + _pipeline : { + source : fragmentShader, + extension : '.glsl' + } + } + }); + + // Add program + var programAttributes = Object.keys(techniqueAttributes); + var programId = addToArray(programs, { + attributes : programAttributes, + fragmentShader : fragmentShaderId, + vertexShader : vertexShaderId + }); + + var techniqueId = addToArray(techniques, { + attributes : techniqueAttributes, + parameters : techniqueParameters, + program : programId, + states : techniqueStates, + uniforms : techniqueUniforms + }); + + return techniqueId; + } + + function getPBRValueType(paramName, paramValue) { + var value; + + switch (paramName) { + case 'baseColorFactor': + return WebGLConstants.FLOAT_VEC4; + case 'metallicFactor': + return WebGLConstants.FLOAT; + case 'roughnessFactor': + return WebGLConstants.FLOAT; + case 'baseColorTexture': + return WebGLConstants.SAMPLER_2D; + case 'metallicRoughnessTexture': + return WebGLConstants.SAMPLER_2D; + case 'normalTexture': + return WebGLConstants.SAMPLER_2D; + case 'occlusionTexture': + return WebGLConstants.SAMPLER_2D; + case 'emissiveTexture': + return WebGLConstants.SAMPLER_2D; + case 'emissiveFactor': + return WebGLConstants.FLOAT_VEC3; + case 'doubleSided': + return WebGLConstants.BOOL; + } + } + + function getShaderVariable(type) { + if (type === 'SCALAR') { + return 'float'; + } + return type.toLowerCase(); + } + + function ensureSemanticExistenceForPrimitive(gltf, primitive) { + var accessors = gltf.accessors; + var materials = gltf.materials; + var techniques = gltf.techniques; + var programs = gltf.programs; + var shaders = gltf.shaders; + var targets = primitive.targets; + + var attributes = primitive.attributes; + for (var target in targets) { + if (defined(target)) { + var targetAttributes = targets[target]; + for (var attribute in targetAttributes) { + if (attribute !== 'extras') { + attributes[attribute + '_' + target] = targetAttributes[attribute]; + } + } + } + } + var material = materials[primitive.material]; + var technique = techniques[material.technique]; + var program = programs[technique.program]; + var vertexShader = shaders[program.vertexShader]; + + for (var semantic in attributes) { + if (attributes.hasOwnProperty(semantic)) { + if (!defined(techniqueParameterForSemantic(technique, semantic))) { + var accessorId = attributes[semantic]; + var accessor = accessors[accessorId]; + if (semantic.charAt(0) === '_') { + semantic = semantic.slice(1); + } + var attributeName = 'a_' + semantic; + technique.parameters[semantic] = { + semantic : semantic, + type : accessor.componentType + }; + technique.attributes[attributeName] = semantic; + program.attributes.push(attributeName); + var pipelineExtras = vertexShader.extras._pipeline; + var shaderText = pipelineExtras.source; + shaderText = 'attribute ' + getShaderVariable(accessor.type) + ' ' + attributeName + ';\n' + shaderText; + pipelineExtras.source = shaderText; + } + } + } + } + + function ensureSemanticExistence(gltf) { + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + ensureSemanticExistenceForPrimitive(gltf, primitive); + }); + }); + } + + function splitIncompatibleSkins(gltf) { + var accessors = gltf.accessors; + var materials = gltf.materials; + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + var materialId = primitive.material; + var material = materials[materialId]; + + var jointAccessorId = primitive.attributes.JOINTS_0; + var componentType; + var type; + if (defined(jointAccessorId)) { + var jointAccessor = accessors[jointAccessorId]; + componentType = jointAccessor.componentType; + type = jointAccessor.type; + } + var isSkinned = defined(jointAccessorId); + + var skinningInfo = material.extras._pipeline.skinning; + if (!defined(skinningInfo)) { + material.extras._pipeline.skinning = { + skinned : isSkinned, + componentType : componentType, + type : type + }; + } else if ((skinningInfo.skinned !== isSkinned) || (skinningInfo.type !== type)) { + // This primitive uses the same material as another one that either isn't skinned or uses a different type to store joints and weights + var clonedMaterial = clone(material, true); + clonedMaterial.material.extras._pipeline.skinning = { + skinned : isSkinned, + componentType : componentType, + type : type + }; + // Split this off as a separate material + materialId = addToArray(materials, clonedMaterial); + primitive.material = materialId; + } + }); + }); + } + + return processPbrMetallicRoughness; +}); diff --git a/Source/ThirdParty/GltfPipeline/removeExtensionsRequired.js b/Source/ThirdParty/GltfPipeline/removeExtensionsRequired.js new file mode 100644 index 000000000000..54d8002887bb --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/removeExtensionsRequired.js @@ -0,0 +1,27 @@ +define([ + '../../Core/defined' + ], function( + defined) { + 'use strict'; + + /** + * Removes an extension from gltf.extensionsRequired if it is present. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {String} extension The extension to remove. + */ + function removeExtensionsRequired(gltf, extension) { + var extensionsRequired = gltf.extensionsRequired; + if (defined(extensionsRequired)) { + var index = extensionsRequired.indexOf(extension); + if (index >= 0) { + extensionsRequired.splice(index, 1); + } + if (extensionsRequired.length === 0) { + delete gltf.extensionsRequired; + } + } + } + + return removeExtensionsRequired; +}); diff --git a/Source/ThirdParty/GltfPipeline/removeExtensionsUsed.js b/Source/ThirdParty/GltfPipeline/removeExtensionsUsed.js new file mode 100644 index 000000000000..f3fc28de7bca --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/removeExtensionsUsed.js @@ -0,0 +1,29 @@ +define([ + './removeExtensionsRequired', + '../../Core/defined' + ], function( + removeExtensionsRequired, + defined) { + 'use strict'; + + /** + * Removes an extension from gltf.extensionsUsed and gltf.extensionsRequired if it is present. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {String} extension The extension to remove. + */ + function removeExtensionsUsed(gltf, extension) { + var extensionsUsed = gltf.extensionsUsed; + if (defined(extensionsUsed)) { + var index = extensionsUsed.indexOf(extension); + if (index >= 0) { + extensionsUsed.splice(index, 1); + } + removeExtensionsRequired(gltf, extension); + if (extensionsUsed.length === 0) { + delete gltf.extensionsUsed; + } + } + } + return removeExtensionsUsed; +}); diff --git a/Source/ThirdParty/GltfPipeline/removePipelineExtras.js b/Source/ThirdParty/GltfPipeline/removePipelineExtras.js new file mode 100644 index 000000000000..abe075ca8a75 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/removePipelineExtras.js @@ -0,0 +1,34 @@ +define([ + '../../Core/defined' + ], function( + defined) { + 'use strict'; + + /** + * Iterate through the objects within each glTF object and delete their pipeline extras object. + * + * @param {Object} object Root object to remove pipeline extras. + * @returns {Object} glTF with no pipeline extras. + */ + function removePipelineExtras(object) { + if (defined(object) && typeof object === 'object') { + if (defined(object.extras) && defined(object.extras._pipeline)) { + delete object.extras._pipeline; + // Also delete extras if extras._pipeline is the only extras object + if (Object.keys(object.extras).length === 0) { + delete object.extras; + } + } + + //Recursively check subproperties for extras + for (var propertyId in object) { + if (object.hasOwnProperty(propertyId)) { + removePipelineExtras(object[propertyId]); + } + } + } + + return object; + } + return removePipelineExtras; +}); diff --git a/Source/ThirdParty/GltfPipeline/techniqueParameterForSemantic.js b/Source/ThirdParty/GltfPipeline/techniqueParameterForSemantic.js new file mode 100644 index 000000000000..a0dc6adfe587 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/techniqueParameterForSemantic.js @@ -0,0 +1,29 @@ +define([ + '../../Core/defined' + ], function( + defined) { + 'use strict'; + + /** + * Retrieves the technique parameter that has a matching semantic. + * + * @param {Object} technique A javascript object containing a glTF technique. + * @param {String} semantic The search string for semantics. + * @returns {String} The technique parameter with matching semantic. + * + * @private + */ + function techniqueParameterForSemantic(technique, semantic) { + var parameters = technique.parameters; + for (var parameterName in parameters) { + if (parameters.hasOwnProperty(parameterName)) { + var parameter = parameters[parameterName]; + var parameterSemantic = parameter.semantic; + if (defined(parameterSemantic) && parameterSemantic === semantic) { + return parameterName; + } + } + } + } + return techniqueParameterForSemantic; +}); diff --git a/Source/ThirdParty/GltfPipeline/updateVersion.js b/Source/ThirdParty/GltfPipeline/updateVersion.js new file mode 100644 index 000000000000..d832de0ebbb4 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/updateVersion.js @@ -0,0 +1,859 @@ +define([ + './addExtensionsRequired', + './addToArray', + './findAccessorMinMax', + './ForEach', + './getAccessorByteStride', + '../../Core/Cartesian3', + '../../Core/Math', + '../../Core/clone', + '../../Core/defaultValue', + '../../Core/defined', + '../../Core/Quaternion', + '../../Core/WebGLConstants' + ], function( + addExtensionsRequired, + addToArray, + findAccessorMinMax, + ForEach, + getAccessorByteStride, + Cartesian3, + CesiumMath, + clone, + defaultValue, + defined, + Quaternion, + WebGLConstants) { + 'use strict'; + + var updateFunctions = { + '0.8' : glTF08to10, + '1.0' : glTF10to20, + '2.0' : undefined + }; + + /** + * Update the glTF version to the latest version (2.0), or targetVersion if specified. + * Applies changes made to the glTF spec between revisions so that the core library + * only has to handle the latest version. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {Object} [options] Options for updating the glTF. + * @param {String} [options.targetVersion] The glTF will be upgraded until it hits the specified version. + * @returns {Object} The updated glTF asset. + */ + function updateVersion(gltf, options) { + options = defaultValue(options, {}); + var targetVersion = options.targetVersion; + var version = gltf.version; + + gltf.asset = defaultValue(gltf.asset, { + version: '1.0' + }); + + version = defaultValue(version, gltf.asset.version); + // invalid version + if (!updateFunctions.hasOwnProperty(version)) { + // try truncating trailing version numbers, could be a number as well if it is 0.8 + if (defined(version)) { + version = ('' + version).substring(0, 3); + } + // default to 1.0 if it cannot be determined + if (!updateFunctions.hasOwnProperty(version)) { + version = '1.0'; + } + } + + var updateFunction = updateFunctions[version]; + + while (defined(updateFunction)) { + if (version === targetVersion) { + break; + } + updateFunction(gltf); + version = gltf.asset.version; + updateFunction = updateFunctions[version]; + } + return gltf; + } + + function updateInstanceTechniques(gltf) { + var materials = gltf.materials; + for (var materialId in materials) { + if (materials.hasOwnProperty(materialId)) { + var material = materials[materialId]; + var instanceTechnique = material.instanceTechnique; + if (defined(instanceTechnique)) { + material.technique = instanceTechnique.technique; + material.values = instanceTechnique.values; + delete material.instanceTechnique; + } + } + } + } + + function setPrimitiveModes(gltf) { + var meshes = gltf.meshes; + for (var meshId in meshes) { + if (meshes.hasOwnProperty(meshId)) { + var mesh = meshes[meshId]; + var primitives = mesh.primitives; + if (defined(primitives)) { + var primitivesLength = primitives.length; + for (var i = 0; i < primitivesLength; i++) { + var primitive = primitives[i]; + var defaultMode = defaultValue(primitive.primitive, WebGLConstants.TRIANGLES); + primitive.mode = defaultValue(primitive.mode, defaultMode); + delete primitive.primitive; + } + } + } + } + } + + function updateNodes(gltf) { + var nodes = gltf.nodes; + var axis = new Cartesian3(); + var quat = new Quaternion(); + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + var node = nodes[nodeId]; + if (defined(node.rotation)) { + var rotation = node.rotation; + Cartesian3.fromArray(rotation, 0, axis); + Quaternion.fromAxisAngle(axis, rotation[3], quat); + node.rotation = [quat.x, quat.y, quat.z, quat.w]; + } + var instanceSkin = node.instanceSkin; + if (defined(instanceSkin)) { + node.skeletons = instanceSkin.skeletons; + node.skin = instanceSkin.skin; + node.meshes = instanceSkin.meshes; + delete node.instanceSkin; + } + } + } + } + + function removeTechniquePasses(gltf) { + var techniques = gltf.techniques; + for (var techniqueId in techniques) { + if (techniques.hasOwnProperty(techniqueId)) { + var technique = techniques[techniqueId]; + var passes = technique.passes; + if (defined(passes)) { + var passName = defaultValue(technique.pass, 'defaultPass'); + if (passes.hasOwnProperty(passName)) { + var pass = passes[passName]; + var instanceProgram = pass.instanceProgram; + technique.attributes = defaultValue(technique.attributes, instanceProgram.attributes); + technique.program = defaultValue(technique.program, instanceProgram.program); + technique.uniforms = defaultValue(technique.uniforms, instanceProgram.uniforms); + technique.states = defaultValue(technique.states, pass.states); + } + delete technique.passes; + delete technique.pass; + } + } + } + } + + function glTF08to10(gltf) { + if (!defined(gltf.asset)) { + gltf.asset = {}; + } + var asset = gltf.asset; + asset.version = '1.0'; + // profile should be an object, not a string + if (!defined(asset.profile) || (typeof asset.profile === 'string')) { + asset.profile = {}; + } + // version property should be in asset, not on the root element + if (defined(gltf.version)) { + delete gltf.version; + } + // material.instanceTechnique properties should be directly on the material + updateInstanceTechniques(gltf); + // primitive.primitive should be primitive.mode + setPrimitiveModes(gltf); + // node rotation should be quaternion, not axis-angle + // node.instanceSkin is deprecated + updateNodes(gltf); + // technique.pass and techniques.passes are deprecated + removeTechniquePasses(gltf); + // gltf.lights -> khrMaterialsCommon.lights + if (defined(gltf.lights)) { + var extensions = defaultValue(gltf.extensions, {}); + gltf.extensions = extensions; + var materialsCommon = defaultValue(extensions.KHR_materials_common, {}); + extensions.KHR_materials_common = materialsCommon; + materialsCommon.lights = gltf.lights; + delete gltf.lights; + } + // gltf.allExtensions -> extensionsUsed + if (defined(gltf.allExtensions)) { + gltf.extensionsUsed = gltf.allExtensions; + gltf.allExtensions = undefined; + } + } + + function removeAnimationSamplersIndirection(gltf) { + var animations = gltf.animations; + for (var animationId in animations) { + if (animations.hasOwnProperty(animationId)) { + var animation = animations[animationId]; + var parameters = animation.parameters; + if (defined(parameters)) { + var samplers = animation.samplers; + for (var samplerId in samplers) { + if (samplers.hasOwnProperty(samplerId)) { + var sampler = samplers[samplerId]; + sampler.input = parameters[sampler.input]; + sampler.output = parameters[sampler.output]; + } + } + delete animation.parameters; + } + } + } + } + + function objectToArray(object, mapping) { + var array = []; + for (var id in object) { + if (object.hasOwnProperty(id)) { + var value = object[id]; + mapping[id] = array.length; + array.push(value); + if (!defined(value.name)) { + value.name = id; + } + } + } + return array; + } + + function objectsToArrays(gltf) { + var i; + var globalMapping = { + accessors: {}, + animations: {}, + bufferViews: {}, + buffers: {}, + cameras: {}, + materials: {}, + meshes: {}, + nodes: {}, + programs: {}, + shaders: {}, + skins: {}, + techniques: {} + }; + + // Map joint names to id names + var jointName; + var jointNameToId = {}; + var nodes = gltf.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + jointName = nodes[id].jointName; + if (defined(jointName)) { + jointNameToId[jointName] = id; + } + } + } + + // Convert top level objects to arrays + for (var topLevelId in gltf) { + if (gltf.hasOwnProperty(topLevelId) && topLevelId !== 'extras' && topLevelId !== 'asset' && topLevelId !== 'extensions') { + var objectMapping = {}; + var object = gltf[topLevelId]; + if (typeof(object) === 'object' && !Array.isArray(object)) { + gltf[topLevelId] = objectToArray(object, objectMapping); + globalMapping[topLevelId] = objectMapping; + if (topLevelId === 'animations') { + objectMapping = {}; + object.samplers = objectToArray(object.samplers, objectMapping); + globalMapping[topLevelId].samplers = objectMapping; + } + } + } + } + + // Remap joint names to array indexes + for (jointName in jointNameToId) { + if (jointNameToId.hasOwnProperty(jointName)) { + jointNameToId[jointName] = globalMapping.nodes[jointNameToId[jointName]]; + } + } + + // Fix references + if (defined(gltf.scene)) { + gltf.scene = globalMapping.scenes[gltf.scene]; + } + ForEach.bufferView(gltf, function(bufferView) { + if (defined(bufferView.buffer)) { + bufferView.buffer = globalMapping.buffers[bufferView.buffer]; + } + }); + ForEach.accessor(gltf, function(accessor) { + if (defined(accessor.bufferView)) { + accessor.bufferView = globalMapping.bufferViews[accessor.bufferView]; + } + }); + ForEach.shader(gltf, function(shader) { + var extensions = shader.extensions; + if (defined(extensions)) { + var binaryGltf = extensions.KHR_binary_glTF; + if (defined(binaryGltf)) { + shader.bufferView = globalMapping.bufferViews[binaryGltf.bufferView]; + delete extensions.KHR_binary_glTF; + } + if (Object.keys(extensions).length === 0) { + delete shader.extensions; + } + } + }); + ForEach.program(gltf, function(program) { + if (defined(program.vertexShader)) { + program.vertexShader = globalMapping.shaders[program.vertexShader]; + } + if (defined(program.fragmentShader)) { + program.fragmentShader = globalMapping.shaders[program.fragmentShader]; + } + }); + ForEach.technique(gltf, function(technique) { + if (defined(technique.program)) { + technique.program = globalMapping.programs[technique.program]; + } + ForEach.techniqueParameter(technique, function(parameter) { + if (defined(parameter.node)) { + parameter.node = globalMapping.nodes[parameter.node]; + } + var value = parameter.value; + if (defined(value)) { + if (Array.isArray(value)) { + if (value.length === 1) { + var textureId = value[0]; + if (typeof textureId === 'string') { + value[0] = globalMapping.textures[textureId]; + } + } + } + else if (typeof value === 'string') { + parameter.value = [globalMapping.textures[value]]; + } + } + }); + }); + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + if (defined(primitive.indices)) { + primitive.indices = globalMapping.accessors[primitive.indices]; + } + ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { + primitive.attributes[semantic] = globalMapping.accessors[accessorId]; + }); + if (defined(primitive.material)) { + primitive.material = globalMapping.materials[primitive.material]; + } + }); + }); + ForEach.node(gltf, function(node) { + var children = node.children; + if (defined(children)) { + var childrenLength = children.length; + for (i = 0; i < childrenLength; i++) { + children[i] = globalMapping.nodes[children[i]]; + } + } + if (defined(node.meshes)) { + // Split out meshes on nodes + var meshes = node.meshes; + var meshesLength = meshes.length; + if (meshesLength > 0) { + node.mesh = globalMapping.meshes[meshes[0]]; + for (i = 1; i < meshesLength; i++) { + var meshNode = { + mesh: globalMapping.meshes[meshes[i]], + extras: { + _pipeline: {} + } + }; + var meshNodeId = addToArray(gltf.nodes, meshNode); + if (!defined(children)) { + children = []; + node.children = children; + } + children.push(meshNodeId); + } + } + delete node.meshes; + } + if (defined(node.camera)) { + node.camera = globalMapping.cameras[node.camera]; + } + if (defined(node.skeletons)) { + // Assign skeletons to skins + var skeletons = node.skeletons; + var skeletonsLength = skeletons.length; + if ((skeletonsLength > 0) && defined(node.skin)) { + var skin = gltf.skins[globalMapping.skins[node.skin]]; + skin.skeleton = globalMapping.nodes[skeletons[0]]; + } + delete node.skeletons; + } + if (defined(node.skin)) { + node.skin = globalMapping.skins[node.skin]; + } + if (defined(node.jointName)) { + delete(node.jointName); + } + }); + ForEach.skin(gltf, function(skin) { + if (defined(skin.inverseBindMatrices)) { + skin.inverseBindMatrices = globalMapping.accessors[skin.inverseBindMatrices]; + } + var joints = []; + var jointNames = skin.jointNames; + if (defined(jointNames)) { + for (i = 0; i < jointNames.length; i++) { + joints[i] = jointNameToId[jointNames[i]]; + } + skin.joints = joints; + delete skin.jointNames; + } + }); + ForEach.scene(gltf, function(scene) { + var sceneNodes = scene.nodes; + if (defined(sceneNodes)) { + var sceneNodesLength = sceneNodes.length; + for (i = 0; i < sceneNodesLength; i++) { + sceneNodes[i] = globalMapping.nodes[sceneNodes[i]]; + } + } + }); + ForEach.animation(gltf, function(animation) { + var samplerMapping = {}; + animation.samplers = objectToArray(animation.samplers, samplerMapping); + ForEach.animationSampler(animation, function(sampler) { + sampler.input = globalMapping.accessors[sampler.input]; + sampler.output = globalMapping.accessors[sampler.output]; + }); + var channels = animation.channels; + if (defined(channels)) { + var channelsLength = channels.length; + for (i = 0; i < channelsLength; i++) { + var channel = channels[i]; + channel.sampler = samplerMapping[channel.sampler]; + var target = channel.target; + if (defined(target)) { + target.node = globalMapping.nodes[target.id]; + } + } + } + }); + ForEach.material(gltf, function(material) { + if (defined(material.technique)) { + material.technique = globalMapping.techniques[material.technique]; + } + ForEach.materialValue(material, function(value, name) { + if (Array.isArray(value)) { + if (value.length === 1) { + var textureId = value[0]; + if (typeof textureId === 'string') { + value[0] = globalMapping.textures[textureId]; + } + } + } + else if (typeof value === 'string') { + material.values[name] = { + index : globalMapping.textures[value] + }; + } + }); + var extensions = material.extensions; + if (defined(extensions)) { + var materialsCommon = extensions.KHR_materials_common; + if (defined(materialsCommon)) { + ForEach.materialValue(materialsCommon, function(value, name) { + if (Array.isArray(value)) { + if (value.length === 1) { + var textureId = value[0]; + if (typeof textureId === 'string') { + value[0] = globalMapping.textures[textureId]; + } + } + } + else if (typeof value === 'string') { + materialsCommon.values[name] = { + index: globalMapping.textures[value] + }; + } + }); + } + } + }); + ForEach.image(gltf, function(image) { + var extensions = image.extensions; + if (defined(extensions)) { + var binaryGltf = extensions.KHR_binary_glTF; + if (defined(binaryGltf)) { + image.bufferView = globalMapping.bufferViews[binaryGltf.bufferView]; + image.mimeType = binaryGltf.mimeType; + delete extensions.KHR_binary_glTF; + } + if (Object.keys(extensions).length === 0) { + delete image.extensions; + } + } + }); + ForEach.texture(gltf, function(texture) { + if (defined(texture.sampler)) { + texture.sampler = globalMapping.samplers[texture.sampler]; + } + if (defined(texture.source)) { + texture.source = globalMapping.images[texture.source]; + } + }); + } + + function stripProfile(gltf) { + var asset = gltf.asset; + delete asset.profile; + } + + var knownExtensions = { + CESIUM_RTC : true, + KHR_materials_common : true, + WEB3D_quantized_attributes : true + }; + function requireKnownExtensions(gltf) { + var extensionsUsed = gltf.extensionsUsed; + gltf.extensionsRequired = defaultValue(gltf.extensionsRequired, []); + if (defined(extensionsUsed)) { + var extensionsUsedLength = extensionsUsed.length; + for (var i = 0; i < extensionsUsedLength; i++) { + var extension = extensionsUsed[i]; + if (defined(knownExtensions[extension])) { + gltf.extensionsRequired.push(extension); + } + } + } + } + + function removeBufferType(gltf) { + ForEach.buffer(gltf, function(buffer) { + delete buffer.type; + }); + } + + function requireAttributeSetIndex(gltf) { + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { + if (semantic === 'TEXCOORD') { + primitive.attributes.TEXCOORD_0 = accessorId; + } else if (semantic === 'COLOR') { + primitive.attributes.COLOR_0 = accessorId; + } + }); + delete primitive.attributes.TEXCOORD; + delete primitive.attributes.COLOR; + }); + }); + ForEach.technique(gltf, function(technique) { + ForEach.techniqueParameter(technique, function(parameter) { + var semantic = parameter.semantic; + if (defined(semantic)) { + if (semantic === 'TEXCOORD') { + parameter.semantic = 'TEXCOORD_0'; + } else if (semantic === 'COLOR') { + parameter.semantic = 'COLOR_0'; + } + } + }); + }); + } + + var knownSemantics = { + POSITION: true, + NORMAL: true, + TEXCOORD: true, + COLOR: true, + JOINT: true, + WEIGHT: true + }; + function underscoreApplicationSpecificSemantics(gltf) { + var mappedSemantics = {}; + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + /* jshint unused:vars */ + ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { + if (semantic.charAt(0) !== '_') { + var setIndex = semantic.search(/_[0-9]+/g); + var strippedSemantic = semantic; + if (setIndex >= 0) { + strippedSemantic = semantic.substring(0, setIndex); + } + if (!defined(knownSemantics[strippedSemantic])) { + var newSemantic = '_' + semantic; + mappedSemantics[semantic] = newSemantic; + } + } + }); + for (var semantic in mappedSemantics) { + if (mappedSemantics.hasOwnProperty(semantic)) { + var mappedSemantic = mappedSemantics[semantic]; + var accessorId = primitive.attributes[semantic]; + if (defined(accessorId)) { + delete primitive.attributes[semantic]; + primitive.attributes[mappedSemantic] = accessorId; + } + } + } + }); + }); + ForEach.technique(gltf, function(technique) { + ForEach.techniqueParameter(technique, function(parameter) { + var mappedSemantic = mappedSemantics[parameter.semantic]; + if (defined(mappedSemantic)) { + parameter.semantic = mappedSemantic; + } + }); + }); + } + + function makeTechniqueValuesArrays(gltf) { + ForEach.technique(gltf, function(technique) { + ForEach.techniqueParameter(technique, function(parameter) { + var value = parameter.value; + if (defined(value) && !Array.isArray(value)) { + parameter.value = [value]; + } + }); + }); + } + + function removeScissorFromTechniques(gltf) { + ForEach.technique(gltf, function(technique) { + var techniqueStates = technique.states; + if (defined(techniqueStates)) { + var techniqueFunctions = techniqueStates.functions; + if (defined(techniqueFunctions)) { + delete techniqueFunctions.scissor; + } + var enableStates = techniqueStates.enable; + if (defined(enableStates)) { + var scissorIndex = enableStates.indexOf(WebGLConstants.SCISSOR_TEST); + if (scissorIndex >= 0) { + enableStates.splice(scissorIndex, 1); + } + } + } + }); + } + + function clampTechniqueFunctionStates(gltf) { + ForEach.technique(gltf, function(technique) { + var techniqueStates = technique.states; + if (defined(techniqueStates)) { + var functions = techniqueStates.functions; + if (defined(functions)) { + var blendColor = functions.blendColor; + if (defined(blendColor)) { + for (var i = 0; i < 4; i++) { + blendColor[i] = CesiumMath.clamp(blendColor[i], 0.0, 1.0); + } + } + var depthRange = functions.depthRange; + if (defined(depthRange)) { + depthRange[1] = CesiumMath.clamp(depthRange[1], 0.0, 1.0); + depthRange[0] = CesiumMath.clamp(depthRange[0], 0.0, depthRange[1]); + } + } + } + }); + } + + function clampCameraParameters(gltf) { + ForEach.camera(gltf, function(camera) { + var perspective = camera.perspective; + if (defined(perspective)) { + var aspectRatio = perspective.aspectRatio; + if (defined(aspectRatio) && aspectRatio === 0.0) { + delete perspective.aspectRatio; + } + var yfov = perspective.yfov; + if (defined(yfov) && yfov === 0.0) { + perspective.yfov = 1.0; + } + } + }); + } + + function requireByteLength(gltf) { + ForEach.buffer(gltf, function(buffer) { + if (!defined(buffer.byteLength)) { + buffer.byteLength = buffer.extras._pipeline.source.length; + } + }); + ForEach.bufferView(gltf, function(bufferView) { + if (!defined(bufferView.byteLength)) { + var bufferViewBufferId = bufferView.buffer; + var bufferViewBuffer = gltf.buffers[bufferViewBufferId]; + bufferView.byteLength = bufferViewBuffer.byteLength; + } + }); + } + + function moveByteStrideToBufferView(gltf) { + var bufferViews = gltf.bufferViews; + var bufferViewsToDelete = {}; + ForEach.accessor(gltf, function(accessor) { + var oldBufferViewId = accessor.bufferView; + if (defined(oldBufferViewId)) { + if (!defined(bufferViewsToDelete[oldBufferViewId])) { + bufferViewsToDelete[oldBufferViewId] = true; + } + var bufferView = clone(bufferViews[oldBufferViewId]); + var accessorByteStride = getAccessorByteStride(gltf, accessor); + if (defined(accessorByteStride)) { + bufferView.byteStride = accessorByteStride; + if (bufferView.byteStride !== 0) { + bufferView.byteLength = accessor.count * accessorByteStride; + } + bufferView.byteOffset += accessor.byteOffset; + accessor.byteOffset = 0; + delete accessor.byteStride; + } + accessor.bufferView = addToArray(bufferViews, bufferView); + } + }); + + var bufferViewShiftMap = {}; + var bufferViewRemovalCount = 0; + ForEach.bufferView(gltf, function(bufferView, bufferViewId) { + if (defined(bufferViewsToDelete[bufferViewId])) { + bufferViewRemovalCount++; + } else { + bufferViewShiftMap[bufferViewId] = bufferViewId - bufferViewRemovalCount; + } + }); + + var removedCount = 0; + for (var bufferViewId in bufferViewsToDelete) { + if (defined(bufferViewId)) { + var index = parseInt(bufferViewId) - removedCount; + bufferViews.splice(index, 1); + removedCount++; + } + } + + ForEach.accessor(gltf, function(accessor) { + var accessorBufferView = accessor.bufferView; + if (defined(accessorBufferView)) { + accessor.bufferView = bufferViewShiftMap[accessorBufferView]; + } + }); + + ForEach.shader(gltf, function(shader) { + var shaderBufferView = shader.bufferView; + if (defined(shaderBufferView)) { + shader.bufferView = bufferViewShiftMap[shaderBufferView]; + } + }); + + ForEach.image(gltf, function(image) { + var imageBufferView = image.bufferView; + if (defined(imageBufferView)) { + image.bufferView = bufferViewShiftMap[imageBufferView]; + } + }); + } + + function requireAccessorMinMax(gltf) { + ForEach.accessor(gltf, function(accessor) { + if (!defined(accessor.min) || !defined(accessor.max)) { + var minMax = findAccessorMinMax(gltf, accessor); + accessor.min = minMax.min; + accessor.max = minMax.max; + } + }); + } + + function stripTechniqueAttributeValues(gltf) { + ForEach.technique(gltf, function(technique) { + ForEach.techniqueAttribute(technique, function(attribute) { + var parameter = technique.parameters[attribute]; + if (defined(parameter.value)) { + delete parameter.value; + } + }); + }); + } + + function stripTechniqueParameterCount(gltf) { + ForEach.technique(gltf, function(technique) { + ForEach.techniqueParameter(technique, function(parameter) { + if (defined(parameter.count)) { + var semantic = parameter.semantic; + if (!defined(semantic) || (semantic !== 'JOINTMATRIX' && semantic.indexOf('_') !== 0)) { + delete parameter.count; + } + } + }); + }); + } + + function addKHRTechniqueExtension(gltf) { + var techniques = gltf.techniques; + if (defined(techniques) && techniques.length > 0) { + addExtensionsRequired(gltf, 'KHR_technique_webgl'); + } + } + + function glTF10to20(gltf) { + if (!defined(gltf.asset)) { + gltf.asset = {}; + } + var asset = gltf.asset; + asset.version = '2.0'; + // material.instanceTechnique properties should be directly on the material. instanceTechnique is a gltf 0.8 property but is seen in some 1.0 models. + updateInstanceTechniques(gltf); + // animation.samplers now refers directly to accessors and animation.parameters should be removed + removeAnimationSamplersIndirection(gltf); + // top-level objects are now arrays referenced by index instead of id + objectsToArrays(gltf); + // asset.profile no longer exists + stripProfile(gltf); + // move known extensions from extensionsUsed to extensionsRequired + requireKnownExtensions(gltf); + // bufferView.byteLength and buffer.byteLength are required + requireByteLength(gltf); + // byteStride moved from accessor to bufferView + moveByteStrideToBufferView(gltf); + // buffer.type is unnecessary and should be removed + removeBufferType(gltf); + // TEXCOORD and COLOR attributes must be written with a set index (TEXCOORD_#) + requireAttributeSetIndex(gltf); + // Add underscores to application-specific parameters + underscoreApplicationSpecificSemantics(gltf); + // technique.parameters.value should be arrays + makeTechniqueValuesArrays(gltf); + // remove scissor from techniques + removeScissorFromTechniques(gltf); + // clamp technique function states to min/max + clampTechniqueFunctionStates(gltf); + // clamp camera parameters + clampCameraParameters(gltf); + // a technique parameter specified as an attribute cannot have a value + stripTechniqueAttributeValues(gltf); + // only techniques with a JOINTMATRIX or application specific semantic may have a defined count property + stripTechniqueParameterCount(gltf); + // add KHR_technique_webgl extension + addKHRTechniqueExtension(gltf); + } + + return updateVersion; +}); diff --git a/Source/ThirdParty/GltfPipeline/webGLConstantToGlslType.js b/Source/ThirdParty/GltfPipeline/webGLConstantToGlslType.js new file mode 100644 index 000000000000..1a7a03716250 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/webGLConstantToGlslType.js @@ -0,0 +1,30 @@ +define([ + '../../Core/WebGLConstants' + ], function( + WebGLConstants) { + 'use strict'; + + function webGLConstantToGlslType(webGLValue) { + switch (webGLValue) { + case WebGLConstants.FLOAT: + return 'float'; + case WebGLConstants.FLOAT_VEC2: + return 'vec2'; + case WebGLConstants.FLOAT_VEC3: + return 'vec3'; + case WebGLConstants.FLOAT_VEC4: + return 'vec4'; + case WebGLConstants.FLOAT_MAT2: + return 'mat2'; + case WebGLConstants.FLOAT_MAT3: + return 'mat3'; + case WebGLConstants.FLOAT_MAT4: + return 'mat4'; + case WebGLConstants.SAMPLER_2D: + return 'sampler2D'; + case WebGLConstants.BOOL: + return 'bool'; + } + } + return webGLConstantToGlslType; +}); diff --git a/Source/ThirdParty/gltfDefaults.js b/Source/ThirdParty/gltfDefaults.js deleted file mode 100644 index 5ca87748bf11..000000000000 --- a/Source/ThirdParty/gltfDefaults.js +++ /dev/null @@ -1,534 +0,0 @@ -define([ - '../Core/Cartesian3', - '../Core/defaultValue', - '../Core/defined', - '../Core/Quaternion', - '../Core/WebGLConstants' - ], function( - Cartesian3, - defaultValue, - defined, - Quaternion, - WebGLConstants) { - "use strict"; - - function accessorDefaults(gltf) { - if (!defined(gltf.accessors)) { - gltf.accessors = {}; - } - var accessors = gltf.accessors; - - for (var name in accessors) { - if (accessors.hasOwnProperty(name)) { - var accessor = accessors[name]; - accessor.byteStride = defaultValue(accessor.byteStride, 0); - } - } - } - - function animationDefaults(gltf) { - if (!defined(gltf.animations)) { - gltf.animations = {}; - } - var animations = gltf.animations; - - for (var name in animations) { - if (animations.hasOwnProperty(name)) { - var animation = animations[name]; - - if (!defined(animation.channels)) { - animation.channels = []; - } - - if (!defined(animation.parameters)) { - animation.parameters = {}; - } - - if (!defined(animation.samplers)) { - animation.samplers = {}; - } - - var samplers = animations.samplers; - - for (var samplerName in samplers) { - if (samplers.hasOwnProperty(samplerName)) { - var sampler = samplers[samplerName]; - sampler.interpolation = defaultValue(sampler.interpolation, 'LINEAR'); - } - } - } - } - } - - function assetDefaults(gltf) { - if (!defined(gltf.asset)) { - gltf.asset = {}; - } - var asset = gltf.asset; - - // Backwards compatibility for glTF 0.8. profile was a string. - if (!defined(asset.profile) || (typeof asset.profile === 'string')) { - asset.profile = {}; - } - var profile = asset.profile; - - asset.premultipliedAlpha = defaultValue(asset.premultipliedAlpha, false); - profile.api = defaultValue(profile.api, 'WebGL'); - profile.version = defaultValue(profile.version, '1.0.2'); - - if (defined(gltf.version)) { - asset.version = defaultValue(asset.version, gltf.version); - delete gltf.version; - } - if (typeof asset.version === 'number') { - asset.version = asset.version.toFixed(1).toString(); - } - } - - function bufferDefaults(gltf) { - if (!defined(gltf.buffers)) { - gltf.buffers = {}; - } - var buffers = gltf.buffers; - - for (var name in buffers) { - if (buffers.hasOwnProperty(name)) { - var buffer = buffers[name]; - buffer.type = defaultValue(buffer.type, 'arraybuffer'); - } - } - } - - function bufferViewDefaults(gltf) { - if (!defined(gltf.bufferViews)) { - gltf.bufferViews = {}; - } - } - - function cameraDefaults(gltf) { - if (!defined(gltf.cameras)) { - gltf.cameras = {}; - } - } - - function imageDefaults(gltf) { - if (!defined(gltf.images)) { - gltf.images = {}; - } - } - - function lightDefaults(gltf) { - if (!defined(gltf.extensions)) { - gltf.extensions = {}; - } - var extensions = gltf.extensions; - - if (!defined(extensions.KHR_materials_common)) { - extensions.KHR_materials_common = {}; - } - var khrMaterialsCommon = extensions.KHR_materials_common; - - if (defined(gltf.lights)) { - khrMaterialsCommon.lights = gltf.lights; - delete gltf.lights; - } - else if (!defined(khrMaterialsCommon.lights)) { - khrMaterialsCommon.lights = {}; - } - var lights = khrMaterialsCommon.lights; - - for (var name in lights) { - if (lights.hasOwnProperty(name)) { - var light = lights[name]; - if (light.type === 'ambient') { - if (!defined(light.ambient)) { - light.ambient = {}; - } - var ambientLight = light.ambient; - - if (!defined(ambientLight.color)) { - ambientLight.color = [1.0, 1.0, 1.0]; - } - } else if (light.type === 'directional') { - if (!defined(light.directional)) { - light.directional = {}; - } - var directionalLight = light.directional; - - if (!defined(directionalLight.color)) { - directionalLight.color = [1.0, 1.0, 1.0]; - } - } else if (light.type === 'point') { - if (!defined(light.point)) { - light.point = {}; - } - var pointLight = light.point; - - if (!defined(pointLight.color)) { - pointLight.color = [1.0, 1.0, 1.0]; - } - - pointLight.constantAttenuation = defaultValue(pointLight.constantAttenuation, 1.0); - pointLight.linearAttenuation = defaultValue(pointLight.linearAttenuation, 0.0); - pointLight.quadraticAttenuation = defaultValue(pointLight.quadraticAttenuation, 0.0); - } else if (light.type === 'spot') { - if (!defined(light.spot)) { - light.spot = {}; - } - var spotLight = light.spot; - - if (!defined(spotLight.color)) { - spotLight.color = [1.0, 1.0, 1.0]; - } - - spotLight.constantAttenuation = defaultValue(spotLight.constantAttenuation, 1.0); - spotLight.fallOffAngle = defaultValue(spotLight.fallOffAngle, 3.14159265); - spotLight.fallOffExponent = defaultValue(spotLight.fallOffExponent, 0.0); - spotLight.linearAttenuation = defaultValue(spotLight.linearAttenuation, 0.0); - spotLight.quadraticAttenuation = defaultValue(spotLight.quadraticAttenuation, 0.0); - } - } - } - } - - function materialDefaults(gltf) { - if (!defined(gltf.materials)) { - gltf.materials = {}; - } - var materials = gltf.materials; - - for (var name in materials) { - if (materials.hasOwnProperty(name)) { - var material = materials[name]; - var instanceTechnique = material.instanceTechnique; - if (defined(instanceTechnique)) { - material.technique = instanceTechnique.technique; - material.values = instanceTechnique.values; - - delete material.instanceTechnique; - } - - if (!defined(material.extensions)) { - if (!defined(material.technique)) { - delete material.values; - material.extensions = { - KHR_materials_common : { - technique : 'CONSTANT', - transparent: false, - values : { - emission : { - type: WebGLConstants.FLOAT_VEC4, - value: [ - 0.5, - 0.5, - 0.5, - 1 - ] - } - } - } - }; - - if (!defined(gltf.extensionsUsed)) { - gltf.extensionsUsed = []; - } - var extensionsUsed = gltf.extensionsUsed; - if (extensionsUsed.indexOf('KHR_materials_common') === -1) { - extensionsUsed.push('KHR_materials_common'); - } - } - else if (!defined(material.values)) { - material.values = {}; - } - } - } - } - } - - function meshDefaults(gltf) { - if (!defined(gltf.meshes)) { - gltf.meshes = {}; - } - var meshes = gltf.meshes; - - for (var name in meshes) { - if (meshes.hasOwnProperty(name)) { - var mesh = meshes[name]; - - if (!defined(mesh.primitives)) { - mesh.primitives = []; - } - - var primitives = mesh.primitives.length; - var length = primitives.length; - for (var i = 0; i < length; ++i) { - var primitive = primitives[i]; - - if (!defined(primitive.attributes)) { - primitive.attributes = {}; - } - - // Backwards compatibility for glTF 0.8. primitive was renamed to mode. - var defaultMode = defaultValue(primitive.primitive, WebGLConstants.TRIANGLES); - - primitive.mode = defaultValue(primitive.mode, defaultMode); - } - } - } - } - - function nodeDefaults(gltf) { - if (!defined(gltf.nodes)) { - gltf.nodes = {}; - } - var nodes = gltf.nodes; - var hasAxisAngle = (parseFloat(gltf.asset.version) < 1.0); - - var axis = new Cartesian3(); - var quat = new Quaternion(); - for (var name in nodes) { - if (nodes.hasOwnProperty(name)) { - var node = nodes[name]; - - if (!defined(node.children)) { - node.children = []; - } - - if (hasAxisAngle && defined(node.rotation)) { - var rotation = node.rotation; - Cartesian3.fromArray(rotation, 0, axis); - Quaternion.fromAxisAngle(axis, rotation[3], quat); - node.rotation = [quat.x, quat.y, quat.z, quat.w]; - } - - if (!defined(node.matrix)) { - // Add default identity matrix if there is no matrix property and no TRS properties - if (!defined(node.translation) && !defined(node.rotation) && !defined(node.scale)) { - node.matrix = [ - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - ]; - } else { - if (!defined(node.translation)) { - node.translation = [0.0, 0.0, 0.0]; - } - - if (!defined(node.rotation)) { - node.rotation = [0.0, 0.0, 0.0, 1.0]; - } - - if (!defined(node.scale)) { - node.scale = [1.0, 1.0, 1.0]; - } - } - } - - var instanceSkin = node.instanceSkin; - if (defined(instanceSkin)) { - node.skeletons = instanceSkin.skeletons; - node.skin = instanceSkin.skin; - node.meshes = instanceSkin.meshes; - delete node.instanceSkin; - } - } - } - } - - function programDefaults(gltf) { - if (!defined(gltf.programs)) { - gltf.programs = {}; - } - var programs = gltf.programs; - - for (var name in programs) { - if (programs.hasOwnProperty(name)) { - var program = programs[name]; - if (!defined(program.attributes)) { - program.attributes = []; - } - } - } - } - - function samplerDefaults(gltf) { - if (!defined(gltf.samplers)) { - gltf.samplers = {}; - } - var samplers = gltf.samplers; - - for (var name in samplers) { - if (samplers.hasOwnProperty(name)) { - var sampler = samplers[name]; - sampler.magFilter = defaultValue(sampler.magFilter, WebGLConstants.LINEAR); - sampler.minFilter = defaultValue(sampler.minFilter, WebGLConstants.NEAREST_MIPMAP_LINEAR); - sampler.wrapS = defaultValue(sampler.wrapS, WebGLConstants.REPEAT); - sampler.wrapT = defaultValue(sampler.wrapT, WebGLConstants.REPEAT); - } - } - } - - function sceneDefaults(gltf) { - if (!defined(gltf.scenes)) { - gltf.scenes = {}; - } - var scenes = gltf.scenes; - - for (var name in scenes) { - if (scenes.hasOwnProperty(name)) { - var scene = scenes[name]; - if (!defined(scene.node)) { - scene.node = []; - } - } - } - } - - function shaderDefaults(gltf) { - if (!defined(gltf.shaders)) { - gltf.shaders = {}; - } - } - - function skinDefaults(gltf) { - if (!defined(gltf.skins)) { - gltf.skins = {}; - } - var skins = gltf.skins; - - for (var name in skins) { - if (skins.hasOwnProperty(name)) { - var skin = skins[name]; - if (!defined(skin.bindShapeMatrix)) { - skin.bindShapeMatrix = [ - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - ]; - } - } - } - } - - function statesDefaults(states) { - if (!defined(states.enable)) { - states.enable = []; - } - - if (!defined(states.disable)) { - states.disable = []; - } - } - - function techniqueDefaults(gltf) { - if (!defined(gltf.techniques)) { - gltf.techniques = {}; - } - var techniques = gltf.techniques; - - for (var name in techniques) { - if (techniques.hasOwnProperty(name)) { - var technique = techniques[name]; - if (!defined(technique.parameters)) { - technique.parameters = {}; - } - var parameters = technique.parameters; - for (var parameterName in parameters) { - var parameter = parameters[parameterName]; - parameter.node = defaultValue(parameter.node, parameter.source); - parameter.source = undefined; - } - - var passes = technique.passes; - if (defined(passes)) { - var passName = defaultValue(technique.pass, 'defaultPass'); - if (passes.hasOwnProperty(passName)) { - var pass = passes[passName]; - var instanceProgram = pass.instanceProgram; - - technique.attributes = defaultValue(technique.attributes, instanceProgram.attributes); - technique.program = defaultValue(technique.program, instanceProgram.program); - technique.uniforms = defaultValue(technique.uniforms, instanceProgram.uniforms); - - technique.states = defaultValue(technique.states, pass.states); - } - - technique.passes = undefined; - technique.pass = undefined; - } - - if (!defined(technique.attributes)) { - technique.attributes = {}; - } - - if (!defined(technique.uniforms)) { - technique.uniforms = {}; - } - - if (!defined(technique.states)) { - technique.states = {}; - } - statesDefaults(technique.states); - } - } - } - - function textureDefaults(gltf) { - if (!defined(gltf.textures)) { - gltf.textures = {}; - } - var textures = gltf.textures; - - for (var name in textures) { - if (textures.hasOwnProperty(name)) { - var texture = textures[name]; - texture.format = defaultValue(texture.format, WebGLConstants.RGBA); - texture.internalFormat = defaultValue(texture.internalFormat, texture.format); - texture.target = defaultValue(texture.target, WebGLConstants.TEXTURE_2D); - texture.type = defaultValue(texture.type, WebGLConstants.UNSIGNED_BYTE); - } - } - } - - /** - * Modifies gltf in place. - * - * @private - */ - var gltfDefaults = function(gltf) { - if (!defined(gltf)) { - return undefined; - } - - if (defined(gltf.allExtensions)) { - gltf.extensionsUsed = gltf.allExtensions; - gltf.allExtensions = undefined; - } - gltf.extensionsUsed = defaultValue(gltf.extensionsUsed, []); - - accessorDefaults(gltf); - animationDefaults(gltf); - assetDefaults(gltf); - bufferDefaults(gltf); - bufferViewDefaults(gltf); - cameraDefaults(gltf); - imageDefaults(gltf); - lightDefaults(gltf); - materialDefaults(gltf); - meshDefaults(gltf); - nodeDefaults(gltf); - programDefaults(gltf); - samplerDefaults(gltf); - sceneDefaults(gltf); - shaderDefaults(gltf); - skinDefaults(gltf); - techniqueDefaults(gltf); - textureDefaults(gltf); - - return gltf; - }; - - return gltfDefaults; -}); diff --git a/Specs/Data/Models/Box-Color/Box-Color.gltf b/Specs/Data/Models/Box-Color/Box-Color.gltf index 995c40cd5309..12d4d5dba33c 100644 --- a/Specs/Data/Models/Box-Color/Box-Color.gltf +++ b/Specs/Data/Models/Box-Color/Box-Color.gltf @@ -1,17 +1,23 @@ { "accessors": { "accessor_21": { - "bufferView": "bufferView_29", + "bufferView": "bufferView_1", "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 36, - "type": "SCALAR" + "type": "SCALAR", + "min": [ + 0 + ], + "max": [ + 23 + ] }, "accessor_23": { - "bufferView": "bufferView_30", + "bufferView": "bufferView_0", "byteOffset": 0, - "byteStride": 12, + "byteStride": 0, "componentType": 5126, "count": 24, "max": [ @@ -27,22 +33,41 @@ "type": "VEC3" }, "accessor_27": { - "bufferView": "bufferView_30", - "byteOffset": 288, - "byteStride": 12, - "componentType": 5126, + "bufferView": "bufferView_0", + "byteOffset": 576, + "byteStride": 0, + "componentType": 5121, "count": 24, "max": [ - 1, - 1, - 1 + 255, + 255, + 255 ], "min": [ 0, 0, 0 ], - "type": "VEC3" + "type": "VEC3", + "normalized": true + }, + "accessor_normal_generated": { + "bufferView": "bufferView_0", + "byteOffset": 288, + "byteStride": 0, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "min": [ + -1, + -1, + -1 + ], + "max": [ + 1, + 1, + 1 + ] } }, "animations": {}, @@ -56,24 +81,24 @@ "version": "1.0" }, "bufferViews": { - "bufferView_29": { - "buffer": "Box", - "byteLength": 72, + "bufferView_0": { + "buffer": "buffer_0", + "byteLength": 648, "byteOffset": 0, - "target": 34963 - }, - "bufferView_30": { - "buffer": "Box", - "byteLength": 576, - "byteOffset": 72, "target": 34962 + }, + "bufferView_1": { + "buffer": "buffer_0", + "byteLength": 72, + "byteOffset": 648, + "target": 34963 } }, "buffers": { - "Box": { - "byteLength": 648, + "buffer_0": { "type": "arraybuffer", - "uri": "data:application/octet-stream;base64,AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUAAAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAD8AAAAAAACAPwAAAD8AAAAAAACAPwAAAD8AAAAAAACAPwAAAD8AAAAAAACAPwAAgD8AAAAAAACAPwAAgD8AAAAAAACAPwAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/lZaWPgAAAACCggI/lZaWPgAAAACCggI/lZaWPgAAAACCggI/lZaWPgAAAACCggI/" + "byteLength": 720, + "uri": "data:application/octet-stream;base64,AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC//wAA/wAA/wAA/wAA/38A/38A/38A/38A//8A//8A//8A//8AAP8AAP8AAP8AAP8AAAD/AAD/AAD/AAD/SgCBSgCBSgCBSgCBAAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA" } }, "materials": { @@ -100,54 +125,29 @@ } }, "nodes": { - "Geometry-mesh002Node": { + "rootNode": { "children": [], - "matrix": [ - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1 - ], "meshes": [ "Geometry-mesh002" ], - "name": "Mesh" - }, - "node_1": { - "children": [ - "Geometry-mesh002Node" - ], "matrix": [ 1, 0, 0, 0, 0, + 1, 0, - -1, 0, 0, - 1, 0, + 1, 0, 0, 0, 0, 1 - ], - "name": "Y_UP_Transform" + ] } }, "programs": { @@ -164,7 +164,7 @@ "scenes": { "defaultScene": { "nodes": [ - "node_1" + "rootNode" ] } }, @@ -230,4 +230,4 @@ }, "samplers": {}, "textures": {} -} \ No newline at end of file +} diff --git a/Specs/Data/Models/Box-Uint32Indices/Box-Uint32Indices.gltf b/Specs/Data/Models/Box-Uint32Indices/Box-Uint32Indices.gltf new file mode 100644 index 000000000000..e456568c2591 --- /dev/null +++ b/Specs/Data/Models/Box-Uint32Indices/Box-Uint32Indices.gltf @@ -0,0 +1,233 @@ +{ + "accessors": { + "accessor_21": { + "bufferView": "bufferView_1", + "byteOffset": 0, + "byteStride": 0, + "componentType": 5125, + "count": 36, + "type": "SCALAR", + "min": [ + 0 + ], + "max": [ + 23 + ] + }, + "accessor_23": { + "bufferView": "bufferView_0", + "byteOffset": 0, + "byteStride": 0, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + "accessor_25": { + "bufferView": "bufferView_0", + "byteOffset": 288, + "byteStride": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1, + 1, + 1 + ], + "min": [ + -1, + -1, + -1 + ], + "type": "VEC3" + } + }, + "animations": {}, + "asset": { + "generator": "collada2gltf@027f74366341d569dea42e9a68b7104cc3892054", + "premultipliedAlpha": true, + "profile": { + "api": "WebGL", + "version": "1.0.2" + }, + "version": "1.0" + }, + "bufferViews": { + "bufferView_0": { + "buffer": "buffer_0", + "byteLength": 576, + "byteOffset": 0, + "target": 34962 + }, + "bufferView_1": { + "buffer": "buffer_0", + "byteLength": 144, + "byteOffset": 576, + "target": 34963 + } + }, + "buffers": { + "buffer_0": { + "type": "arraybuffer", + "byteLength": 720, + "uri": "data:application/octet-stream;base64,AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAC/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAL8AAAC/AAAAPwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAEAAAACAAAAAwAAAAIAAAABAAAABAAAAAUAAAAGAAAABwAAAAYAAAAFAAAACAAAAAkAAAAKAAAACwAAAAoAAAAJAAAADAAAAA0AAAAOAAAADwAAAA4AAAANAAAAEAAAABEAAAASAAAAEwAAABIAAAARAAAAFAAAABUAAAAWAAAAFwAAABYAAAAVAAAA" + } + }, + "materials": { + "Effect-Red": { + "name": "Red", + "technique": "technique0", + "values": { + "diffuse": [ + 0.8, + 0, + 0, + 1 + ], + "shininess": 256, + "specular": [ + 0.2, + 0.2, + 0.2, + 1 + ] + } + } + }, + "meshes": { + "Geometry-mesh002": { + "name": "Mesh", + "primitives": [ + { + "attributes": { + "NORMAL": "accessor_25", + "POSITION": "accessor_23" + }, + "indices": "accessor_21", + "material": "Effect-Red", + "mode": 4 + } + ] + } + }, + "nodes": { + "rootNode": { + "children": [], + "meshes": [ + "Geometry-mesh002" + ], + "matrix": [ + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + ] + } + }, + "programs": { + "program_0": { + "attributes": [ + "a_normal", + "a_position" + ], + "fragmentShader": "Box0FS", + "vertexShader": "Box0VS" + } + }, + "scene": "defaultScene", + "scenes": { + "defaultScene": { + "nodes": [ + "rootNode" + ] + } + }, + "shaders": { + "Box0FS": { + "type": 35632, + "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Owp2YXJ5aW5nIHZlYzMgdl9ub3JtYWw7CnVuaWZvcm0gdmVjNCB1X2RpZmZ1c2U7CnVuaWZvcm0gdmVjNCB1X3NwZWN1bGFyOwp1bmlmb3JtIGZsb2F0IHVfc2hpbmluZXNzOwp2b2lkIG1haW4odm9pZCkgewp2ZWMzIG5vcm1hbCA9IG5vcm1hbGl6ZSh2X25vcm1hbCk7CnZlYzQgY29sb3IgPSB2ZWM0KDAuLCAwLiwgMC4sIDAuKTsKdmVjNCBkaWZmdXNlID0gdmVjNCgwLiwgMC4sIDAuLCAxLik7CnZlYzQgc3BlY3VsYXI7CmRpZmZ1c2UgPSB1X2RpZmZ1c2U7CnNwZWN1bGFyID0gdV9zcGVjdWxhcjsKZGlmZnVzZS54eXogKj0gbWF4KGRvdChub3JtYWwsdmVjMygwLiwwLiwxLikpLCAwLik7CmNvbG9yLnh5eiArPSBkaWZmdXNlLnh5ejsKY29sb3IgPSB2ZWM0KGNvbG9yLnJnYiAqIGRpZmZ1c2UuYSwgZGlmZnVzZS5hKTsKZ2xfRnJhZ0NvbG9yID0gY29sb3I7Cn0K" + }, + "Box0VS": { + "type": 35633, + "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0OwphdHRyaWJ1dGUgdmVjMyBhX3Bvc2l0aW9uOwphdHRyaWJ1dGUgdmVjMyBhX25vcm1hbDsKdmFyeWluZyB2ZWMzIHZfbm9ybWFsOwp1bmlmb3JtIG1hdDMgdV9ub3JtYWxNYXRyaXg7CnVuaWZvcm0gbWF0NCB1X21vZGVsVmlld01hdHJpeDsKdW5pZm9ybSBtYXQ0IHVfcHJvamVjdGlvbk1hdHJpeDsKdm9pZCBtYWluKHZvaWQpIHsKdmVjNCBwb3MgPSB1X21vZGVsVmlld01hdHJpeCAqIHZlYzQoYV9wb3NpdGlvbiwxLjApOwp2X25vcm1hbCA9IHVfbm9ybWFsTWF0cml4ICogYV9ub3JtYWw7CmdsX1Bvc2l0aW9uID0gdV9wcm9qZWN0aW9uTWF0cml4ICogcG9zOwp9Cg==" + } + }, + "skins": {}, + "techniques": { + "technique0": { + "attributes": { + "a_normal": "normal", + "a_position": "position" + }, + "parameters": { + "diffuse": { + "type": 35666 + }, + "modelViewMatrix": { + "semantic": "MODELVIEW", + "type": 35676 + }, + "normal": { + "semantic": "NORMAL", + "type": 35665 + }, + "normalMatrix": { + "semantic": "MODELVIEWINVERSETRANSPOSE", + "type": 35675 + }, + "position": { + "semantic": "POSITION", + "type": 35665 + }, + "projectionMatrix": { + "semantic": "PROJECTION", + "type": 35676 + }, + "shininess": { + "type": 5126 + }, + "specular": { + "type": 35666 + } + }, + "program": "program_0", + "states": { + "enable": [ + 2929, + 2884 + ], + "disable": [] + }, + "uniforms": { + "u_diffuse": "diffuse", + "u_modelViewMatrix": "modelViewMatrix", + "u_normalMatrix": "normalMatrix", + "u_projectionMatrix": "projectionMatrix", + "u_shininess": "shininess", + "u_specular": "specular" + } + } + }, + "glExtensionsUsed": ["OES_element_index_uint"] +} diff --git a/Specs/Data/Models/CesiumAir/Cesium_Air_0_8.gltf b/Specs/Data/Models/CesiumAir/Cesium_Air_0_8.gltf index 24c4eec89283..a5e24adc89e1 100644 --- a/Specs/Data/Models/CesiumAir/Cesium_Air_0_8.gltf +++ b/Specs/Data/Models/CesiumAir/Cesium_Air_0_8.gltf @@ -745,4 +745,4 @@ "type": 5121 } } -} \ No newline at end of file +} diff --git a/Specs/Data/Models/MaterialsCommon/BoxBlinn.gltf b/Specs/Data/Models/MaterialsCommon/BoxBlinn.gltf index 7294d4d46d58..405d09e9af0d 100644 --- a/Specs/Data/Models/MaterialsCommon/BoxBlinn.gltf +++ b/Specs/Data/Models/MaterialsCommon/BoxBlinn.gltf @@ -100,6 +100,12 @@ 0.20000000298023224, 0.20000000298023224, 1 + ], + "ambient": [ + 1, + 0, + 0, + 1 ] } } @@ -183,4 +189,4 @@ } }, "skins": {} -} \ No newline at end of file +} diff --git a/Specs/Data/Models/MaterialsCommon/BoxLambert.gltf b/Specs/Data/Models/MaterialsCommon/BoxLambert.gltf index e481cff78b99..42c1366d9d71 100644 --- a/Specs/Data/Models/MaterialsCommon/BoxLambert.gltf +++ b/Specs/Data/Models/MaterialsCommon/BoxLambert.gltf @@ -93,6 +93,12 @@ 0, 0, 1 + ], + "ambient": [ + 1, + 0, + 0, + 1 ] } } @@ -176,4 +182,4 @@ } }, "skins": {} -} \ No newline at end of file +} diff --git a/Specs/Data/Models/MaterialsCommon/BoxPhong.gltf b/Specs/Data/Models/MaterialsCommon/BoxPhong.gltf index 41d339876b73..73bea2fc2067 100644 --- a/Specs/Data/Models/MaterialsCommon/BoxPhong.gltf +++ b/Specs/Data/Models/MaterialsCommon/BoxPhong.gltf @@ -100,6 +100,12 @@ 0.20000000298023224, 0.20000000298023224, 1 + ], + "ambient": [ + 1, + 0, + 0, + 1 ] } } @@ -183,4 +189,4 @@ } }, "skins": {} -} \ No newline at end of file +} diff --git a/Specs/Data/Models/MaterialsCommon/BoxTransparent.gltf b/Specs/Data/Models/MaterialsCommon/BoxTransparent.gltf index 7a0d33ddcafc..2ef4600ad8dd 100644 --- a/Specs/Data/Models/MaterialsCommon/BoxTransparent.gltf +++ b/Specs/Data/Models/MaterialsCommon/BoxTransparent.gltf @@ -100,6 +100,12 @@ 0.20000000298023224, 0.20000000298023224, 1 + ], + "ambient": [ + 1, + 0, + 0, + 1 ] } } @@ -183,4 +189,4 @@ } }, "skins": {} -} \ No newline at end of file +} diff --git a/Specs/Data/Models/MaterialsCommon/Cesium_Man.gltf b/Specs/Data/Models/MaterialsCommon/Cesium_Man.gltf index 7450e714392a..21b22a328220 100644 --- a/Specs/Data/Models/MaterialsCommon/Cesium_Man.gltf +++ b/Specs/Data/Models/MaterialsCommon/Cesium_Man.gltf @@ -2034,6 +2034,12 @@ 0.20000000298023224, 0.20000000298023224, 1 + ], + "ambient": [ + 1, + 1, + 1, + 1 ] } } @@ -2086,25 +2092,7 @@ ], "name": "Cesium_Man", "skeletons": [ - "locator047Node", - "locator051Node", - "locator055Node", - "locator059Node", - "locator063Node", - "locator071Node", - "locator074Node", - "locator079Node", - "locator082Node", - "locator087Node", - "locator090Node", - "locator103Node", - "locator106Node", - "locator111Node", - "locator114Node", - "locator119Node", - "locator122Node", - "locator135Node", - "locator138Node" + "locator047Node" ], "skin": "Controller-mesh019" }, @@ -2764,4 +2752,4 @@ "type": 5121 } } -} \ No newline at end of file +} diff --git a/Specs/Data/Models/PBR/AnimatedMorphCube/AnimatedMorphCube.gltf b/Specs/Data/Models/PBR/AnimatedMorphCube/AnimatedMorphCube.gltf new file mode 100644 index 000000000000..67debe3545db --- /dev/null +++ b/Specs/Data/Models/PBR/AnimatedMorphCube/AnimatedMorphCube.gltf @@ -0,0 +1 @@ +{"accessors":[{"bufferView":0,"componentType":5126,"count":24,"type":"VEC3","max":[1,1,1],"min":[-1,-1,-1],"byteOffset":0},{"bufferView":1,"componentType":5126,"count":24,"type":"VEC4","max":[1,0,0,1],"min":[1,0,0,1],"byteOffset":0},{"bufferView":2,"componentType":5126,"count":24,"type":"VEC3","max":[0.0100000035,0.0100000035,0.01],"min":[-0.0100000044,-0.0100000054,-0.01],"byteOffset":0},{"bufferView":3,"componentType":5126,"count":24,"type":"VEC3","max":[0,0,0],"min":[0,0,0],"name":"thin","byteOffset":0},{"bufferView":4,"componentType":5126,"count":24,"type":"VEC3","max":[0,0.01893253,0],"min":[0,0,0],"name":"thin","byteOffset":0},{"bufferView":5,"componentType":5126,"count":24,"type":"VEC3","max":[0,0,0],"min":[0,0,0],"name":"thin","byteOffset":0},{"bufferView":6,"componentType":5126,"count":24,"type":"VEC3","max":[0,0,0],"min":[0,0,0],"name":"angle","byteOffset":0},{"bufferView":7,"componentType":5126,"count":24,"type":"VEC3","max":[0,0.0198908355,0],"min":[0,0,0],"name":"angle","byteOffset":0},{"bufferView":8,"componentType":5126,"count":24,"type":"VEC3","max":[0,0,0],"min":[0,0,0],"name":"angle","byteOffset":0},{"bufferView":9,"componentType":5123,"count":36,"type":"SCALAR","max":[23],"min":[0],"byteOffset":0},{"bufferView":10,"componentType":5126,"count":127,"type":"SCALAR","max":[4.19999743],"min":[0],"byteOffset":0},{"bufferView":11,"componentType":5126,"count":254,"type":"SCALAR","max":[1],"min":[-1.52587887e-7],"byteOffset":0}],"animations":[{"channels":[{"sampler":0,"target":{"node":0,"path":"weights"}}],"samplers":[{"input":10,"interpolation":"LINEAR","output":11}],"name":"Square"}],"asset":{"generator":"glTF Tools for Unity","version":"2.0"},"bufferViews":[{"buffer":0,"byteLength":288,"byteOffset":0},{"buffer":0,"byteOffset":288,"byteLength":384},{"buffer":0,"byteOffset":672,"byteLength":288},{"buffer":0,"byteOffset":960,"byteLength":288},{"buffer":0,"byteOffset":1248,"byteLength":288},{"buffer":0,"byteOffset":1536,"byteLength":288},{"buffer":0,"byteOffset":1824,"byteLength":288},{"buffer":0,"byteOffset":2112,"byteLength":288},{"buffer":0,"byteOffset":2400,"byteLength":288},{"buffer":0,"byteOffset":2688,"byteLength":72},{"buffer":0,"byteOffset":2760,"byteLength":508},{"buffer":0,"byteOffset":3268,"byteLength":1016}],"buffers":[{"byteLength":4284,"uri":"data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAvwAAoLQAAACAAACAvwAAoLQAAACAAACAvwAAoLQAAACAAACAvwAAoLQAAACAAQCYNAAAgL8DAEA0AQCYNAAAgL8DAEA0AQCYNAAAgL8DAEA0AQCYNAAAgL8DAEA0AACAPwAAgDT//w80AACAPwAAgDT//w80AACAPwAAgDT//w80AACAPwAAgDT//w80AACAtAAAgD8BADC0AACAtAAAgD8BADC0AACAtAAAgD8BADC0AACAtAAAgD8BADC0AACAPwAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAIA/CtcjvAnXIzwK1yM8BtcjPA7XIzwK1yM8C9cjPAjXI7wK1yM8CtcjvArXI7wK1yM8D9cjvATXIzwK1yO8A9cjvBDXI7wK1yO8DtcjPAbXI7wK1yO8CdcjPArXIzwK1yO8CtcjvAnXIzwK1yM8CtcjvArXI7wK1yM8A9cjvBDXI7wK1yO8D9cjvATXIzwK1yO8CtcjvArXI7wK1yM8C9cjPAjXI7wK1yM8DtcjPAbXI7wK1yO8A9cjvBDXI7wK1yO8C9cjPAjXI7wK1yM8BtcjPA7XIzwK1yM8CdcjPArXIzwK1yO8DtcjPAbXI7wK1yO8D9cjvATXIzwK1yO8CdcjPArXIzwK1yO8BtcjPA7XIzwK1yM8CtcjvAnXIzwK1yM8AAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAGUYmzwAAACAAAAAAGUYmzwAAACAAAAAAAAAAAAAAACAAAAAAGQYmzwAAACAAAAAAGUYmzwAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAGUYmzwAAACAAAAAAGQYmzwAAACAAAAAAAAAAAAAAACAAAAAAGUYmzwAAACAAAAAAGUYmzwAAACAAAAAAGUYmzwAAACAAAAAAGQYmzwAAACAAAAAAGUYmzwAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAGUYmzwAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAABvyojwAAACAAAAAABvyojwAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAABvyojwAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAABvyojwAAACAAAAAABvyojwAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAABvyojwAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgABAAAAAwACAAAA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"}],"meshes":[{"primitives":[{"attributes":{"NORMAL":0,"TANGENT":1,"POSITION":2},"indices":9,"material":0,"targets":[{"NORMAL":3,"POSITION":4,"TANGENT":5},{"NORMAL":6,"POSITION":7,"TANGENT":8}]}],"weights":[0,0],"name":"Cube"}],"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[0.6038274,0.6038274,0.6038274,1],"metallicFactor":0,"roughnessFactor":0.5},"name":"Material"}],"nodes":[{"mesh":0,"rotation":[0.7071068,0,0,0.7071067],"scale":[100,100,100],"name":"AnimatedMorphCube"}],"scene":0,"scenes":[{"nodes":[0]}]} diff --git a/Specs/Data/Models/PBR/BoomBox/BoomBox.bin b/Specs/Data/Models/PBR/BoomBox/BoomBox.bin new file mode 100644 index 000000000000..6e4c9026b1c5 Binary files /dev/null and b/Specs/Data/Models/PBR/BoomBox/BoomBox.bin differ diff --git a/Specs/Data/Models/PBR/BoomBox/BoomBox.gltf b/Specs/Data/Models/PBR/BoomBox/BoomBox.gltf new file mode 100644 index 000000000000..ef9ab24cb3a5 --- /dev/null +++ b/Specs/Data/Models/PBR/BoomBox/BoomBox.gltf @@ -0,0 +1,202 @@ +{ + "accessors": [ + { + "bufferView": 0, + "componentType": 5126, + "count": 3575, + "type": "VEC2", + "max": [ + 0.9999003, + -0.0221377648 + ], + "min": [ + 0.0006585993, + -0.996773958 + ] + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 3575, + "type": "VEC3", + "max": [ + 1.0, + 1.0, + 0.9999782 + ], + "min": [ + -1.0, + -1.0, + -0.9980823 + ] + }, + { + "bufferView": 2, + "componentType": 5126, + "count": 3575, + "type": "VEC4", + "max": [ + 1.0, + 0.9999976, + 1.0, + 1.0 + ], + "min": [ + -0.9991289, + -0.999907851, + -1.0, + 1.0 + ] + }, + { + "bufferView": 3, + "componentType": 5126, + "count": 3575, + "type": "VEC3", + "max": [ + 0.009921154, + 0.00977163, + 0.0100762453 + ], + "min": [ + -0.009921154, + -0.00977163, + -0.0100762453 + ] + }, + { + "bufferView": 4, + "componentType": 5123, + "count": 18108, + "type": "SCALAR", + "max": [ + 3574 + ], + "min": [ + 0 + ] + } + ], + "asset": { + "generator": "glTF Tools for Unity", + "version": "2.0" + }, + "bufferViews": [ + { + "buffer": 0, + "byteLength": 28600 + }, + { + "buffer": 0, + "byteOffset": 28600, + "byteLength": 42900 + }, + { + "buffer": 0, + "byteOffset": 71500, + "byteLength": 57200 + }, + { + "buffer": 0, + "byteOffset": 128700, + "byteLength": 42900 + }, + { + "buffer": 0, + "byteOffset": 171600, + "byteLength": 36216 + } + ], + "buffers": [ + { + "uri": "BoomBox.bin", + "byteLength": 207816 + } + ], + "images": [ + { + "uri": "BoomBox_baseColor.jpg" + }, + { + "uri": "BoomBox_occlusionRoughnessMetallic.jpg" + }, + { + "uri": "BoomBox_normal.png" + }, + { + "uri": "BoomBox_emissive.png" + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "TEXCOORD_0": 0, + "NORMAL": 1, + "TANGENT": 2, + "POSITION": 3 + }, + "indices": 4, + "material": 0 + } + ], + "name": "BoomBox" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicRoughnessTexture": { + "index": 1 + } + }, + "normalTexture": { + "index": 2 + }, + "occlusionTexture": { + "index": 1 + }, + "emissiveFactor": [ + 1.0, + 1.0, + 1.0 + ], + "emissiveTexture": { + "index": 3 + }, + "name": "BoomBox_Mat" + } + ], + "nodes": [ + { + "mesh": 0, + "name": "BoomBox" + } + ], + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "textures": [ + { + "source": 0 + }, + { + "source": 1 + }, + { + "source": 2 + }, + { + "source": 3 + } + ] +} \ No newline at end of file diff --git a/Specs/Data/Models/PBR/BoomBox/BoomBox_baseColor.jpg b/Specs/Data/Models/PBR/BoomBox/BoomBox_baseColor.jpg new file mode 100644 index 000000000000..8c4d33d399d2 Binary files /dev/null and b/Specs/Data/Models/PBR/BoomBox/BoomBox_baseColor.jpg differ diff --git a/Specs/Data/Models/PBR/BoomBox/BoomBox_emissive.png b/Specs/Data/Models/PBR/BoomBox/BoomBox_emissive.png new file mode 100644 index 000000000000..676aab1399a8 Binary files /dev/null and b/Specs/Data/Models/PBR/BoomBox/BoomBox_emissive.png differ diff --git a/Specs/Data/Models/PBR/BoomBox/BoomBox_normal.png b/Specs/Data/Models/PBR/BoomBox/BoomBox_normal.png new file mode 100644 index 000000000000..2f20d5895286 Binary files /dev/null and b/Specs/Data/Models/PBR/BoomBox/BoomBox_normal.png differ diff --git a/Specs/Data/Models/PBR/BoomBox/BoomBox_occlusionRoughnessMetallic.jpg b/Specs/Data/Models/PBR/BoomBox/BoomBox_occlusionRoughnessMetallic.jpg new file mode 100644 index 000000000000..e541030cd39d Binary files /dev/null and b/Specs/Data/Models/PBR/BoomBox/BoomBox_occlusionRoughnessMetallic.jpg differ diff --git a/Specs/Data/Models/PBR/Box/Box.gltf b/Specs/Data/Models/PBR/Box/Box.gltf new file mode 100644 index 000000000000..ea0e8ada690f --- /dev/null +++ b/Specs/Data/Models/PBR/Box/Box.gltf @@ -0,0 +1,142 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.800000011920929, + 0.0, + 0.0, + 1.0 + ], + "metallicFactor": 0.0 + }, + "name": "Red" + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 648, + "uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA" + } + ] +} diff --git a/Specs/Data/Models/PBR/BoxAnimated/BoxAnimated.gltf b/Specs/Data/Models/PBR/BoxAnimated/BoxAnimated.gltf new file mode 100644 index 000000000000..00df92261d5d --- /dev/null +++ b/Specs/Data/Models/PBR/BoxAnimated/BoxAnimated.gltf @@ -0,0 +1 @@ +{"asset":{"generator":"COLLADA2GLTF","version":"2.0"},"scene":0,"scenes":[{"nodes":[3,0]}],"nodes":[{"children":[1],"rotation":[0,0,0,-1]},{"children":[2]},{"mesh":0,"rotation":[0,0,0,-1]},{"mesh":1}],"meshes":[{"primitives":[{"attributes":{"NORMAL":1,"POSITION":2},"indices":0,"mode":4,"material":0}],"name":"inner_box"},{"primitives":[{"attributes":{"NORMAL":4,"POSITION":5},"indices":3,"mode":4,"material":1}],"name":"outer_box"}],"animations":[{"channels":[{"sampler":0,"target":{"node":2,"path":"rotation"}}],"samplers":[{"input":6,"interpolation":"LINEAR","output":7}]},{"channels":[{"sampler":0,"target":{"node":0,"path":"translation"}}],"samplers":[{"input":8,"interpolation":"LINEAR","output":9}]}],"accessors":[{"bufferView":0,"byteOffset":0,"componentType":5123,"count":186,"max":[95],"min":[0],"type":"SCALAR"},{"bufferView":1,"byteOffset":0,"componentType":5126,"count":96,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":1,"byteOffset":1152,"componentType":5126,"count":96,"max":[0.33504000306129456,0.5,0.33504000306129456],"min":[-0.33504000306129456,-0.5,-0.33504000306129456],"type":"VEC3"},{"bufferView":0,"byteOffset":372,"componentType":5123,"count":576,"max":[223],"min":[0],"type":"SCALAR"},{"bufferView":1,"byteOffset":2304,"componentType":5126,"count":224,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":1,"byteOffset":4992,"componentType":5126,"count":224,"max":[0.5,0.5,0.5],"min":[-0.5,-0.5,-0.5],"type":"VEC3"},{"bufferView":2,"byteOffset":0,"componentType":5126,"count":2,"max":[2.5],"min":[1.25],"type":"SCALAR"},{"bufferView":3,"byteOffset":0,"componentType":5126,"count":2,"max":[1,0,0,4.4896593387466766e-11],"min":[0,0,0,-1],"type":"VEC4"},{"bufferView":2,"byteOffset":8,"componentType":5126,"count":4,"max":[3.708329916000366],"min":[0],"type":"SCALAR"},{"bufferView":4,"byteOffset":0,"componentType":5126,"count":4,"max":[0,2.5199999809265137,0],"min":[0,0,0],"type":"VEC3"}],"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[0.800000011920929,0.4159420132637024,0.7952920198440552,1],"metallicFactor":0},"name":"inner"},{"pbrMetallicRoughness":{"baseColorFactor":[0.3016040027141571,0.5335419774055481,0.800000011920929,1],"metallicFactor":0},"name":"outer"}],"bufferViews":[{"buffer":0,"byteOffset":7784,"byteLength":1524,"target":34963},{"buffer":0,"byteOffset":80,"byteLength":7680,"byteStride":12,"target":34962},{"buffer":0,"byteOffset":7760,"byteLength":24},{"buffer":0,"byteOffset":0,"byteLength":32},{"buffer":0,"byteOffset":32,"byteLength":48}],"buffers":[{"byteLength":9308,"uri":"data:application/octet-stream;base64,AAAAgAAAAIAAAACAAACAvwAAgD8AAAAAAAAAABJ1RS4AAAAAAAAAAAAAAAAAAAAArkchQAAAAAAAAAAArkchQAAAAAAAAAAAAAAAAAAAAAAAAAAA9wQ1v/cENT8AAAAA9wQ1v/cENT8AAAAA9wQ1v/cENT8AAAAA9wQ1v/cENT/3BDW/AAAAgPcENb/3BDW/AAAAgPcENb/3BDW/AAAAgPcENb/3BDW/AAAAgPcENb/3BDU/9wQ1vwAAAAD3BDU/9wQ1vwAAAAD3BDU/9wQ1vwAAAAD3BDU/9wQ1vwAAAAD3BDW/9wQ1vwAAAID3BDW/9wQ1vwAAAID3BDW/9wQ1vwAAAID3BDW/9wQ1vwAAAIAAAACA9wQ1v/cENb8AAACA9wQ1v/cENb8AAACA9wQ1v/cENb8AAACA9wQ1v/cENb8AAACA9wQ1P/cENT8AAACA9wQ1P/cENT8AAACA9wQ1P/cENT8AAACA9wQ1P/cENT/3BDU/9wQ1PwAAAAD3BDU/9wQ1PwAAAAD3BDU/9wQ1PwAAAAD3BDU/9wQ1PwAAAAD3BDW/9wQ1PwAAAAD3BDW/9wQ1PwAAAAD3BDW/9wQ1PwAAAAD3BDW/9wQ1PwAAAAD3BDW/AAAAAPcENT/3BDW/AAAAAPcENT/3BDW/AAAAAPcENT/3BDW/AAAAAPcENT8AAAAA9wQ1P/cENb8AAAAA9wQ1P/cENb8AAAAA9wQ1P/cENb8AAAAA9wQ1P/cENb/3BDU/AAAAAPcENT/3BDU/AAAAAPcENT/3BDU/AAAAAPcENT/3BDU/AAAAAPcENT/3BDU/AAAAAPcENb/3BDU/AAAAAPcENb/3BDU/AAAAAPcENb/3BDU/AAAAAPcENb81zRO/Nc0TvzXNE781zRO/Nc0TvzXNE781zRO/Nc0TvzXNE781zRM/Nc0TvzXNE781zRM/Nc0TvzXNE781zRM/Nc0TvzXNE781zRM/Nc0TvzXNEz81zRM/Nc0TvzXNEz81zRM/Nc0TvzXNEz81zRO/Nc0TvzXNEz81zRO/Nc0TvzXNEz81zRO/Nc0TvzXNEz81zRO/Nc0TPzXNE781zRO/Nc0TPzXNE781zRO/Nc0TPzXNE781zRM/Nc0TPzXNE781zRM/Nc0TPzXNE781zRM/Nc0TPzXNE781zRM/Nc0TPzXNEz81zRM/Nc0TPzXNEz81zRM/Nc0TPzXNEz81zRO/Nc0TPzXNEz81zRO/Nc0TPzXNEz81zRO/Nc0TPzXNEz8AAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAIA/AAAAgAAAAAAAAIA/AAAAgAAAAAAAAIA/AAAAgAAAAAAAAIA/AAAAgAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAlAaq+AAAAvyUBqj4lAao+AAAAvyUBqj4lAao+yXb+vl2Kqz4lAaq+yXb+vl2Kqz4lAaq+yXb+Pl2Kq74lAaq+yXb+vl2Kq75diqu+yXb+viUBqr5diqu+yXb+PiUBqr4lAao+AAAAvyUBqj4lAao+AAAAvyUBqr5diqs+yXb+viUBqr5diqs+yXb+viUBqj5diqu+yXb+viUBqj5diqu+yXb+viUBqr4lAaq+AAAAvyUBqr4lAaq+AAAAvyUBqj4lAao+AAAAvyUBqr4lAaq+AAAAvyUBqr4lAaq+yXb+vl2Kq74lAao+yXb+vl2Kq74lAaq+yXb+Pl2Kqz4lAao+yXb+Pl2Kqz4lAao+AAAAPyUBqj4lAaq+AAAAPyUBqj5diqs+yXb+PiUBqj5diqs+yXb+PiUBqr4lAao+AAAAPyUBqr4lAao+AAAAPyUBqj4lAaq+AAAAPyUBqj4lAaq+AAAAPyUBqr5diqu+yXb+PiUBqr5diqu+yXb+PiUBqj5diqu+yXb+PiUBqj5diqu+yXb+viUBqj4lAaq+yXb+vl2Kqz4lAaq+yXb+Pl2Kqz4lAao+yXb+Pl2Kq74lAaq+yXb+Pl2Kq74lAaq+AAAAPyUBqr4lAao+AAAAPyUBqr4lAao+yXb+Pl2Kqz4lAao+yXb+vl2Kqz5diqs+yXb+viUBqj5diqs+yXb+PiUBqj5diqs+yXb+PiUBqr5diqs+yXb+viUBqr4lAao+yXb+vl2Kq74lAao+yXb+Pl2Kq74lAaq+yXb+vl2Kq74lAaq+AAAAvyUBqr5diqu+yXb+viUBqr5diqs+yXb+viUBqr4lAao+AAAAvyUBqr4lAao+yXb+vl2Kq74lAao+yXb+vl2Kqz4lAao+AAAAvyUBqj5diqs+yXb+viUBqj4lAaq+AAAAvyUBqj4lAaq+yXb+vl2Kqz5diqu+yXb+viUBqj4lAaq+AAAAPyUBqr4lAaq+yXb+Pl2Kq75diqu+yXb+PiUBqr4lAao+AAAAPyUBqr5diqs+yXb+PiUBqr4lAao+yXb+Pl2Kq74lAao+AAAAPyUBqj4lAao+yXb+Pl2Kqz5diqs+yXb+PiUBqj5diqu+yXb+PiUBqj4lAaq+yXb+Pl2Kqz4lAaq+AAAAPyUBqj5diqu+yXb+viUBqr5diqu+yXb+viUBqj5diqu+yXb+PiUBqj5diqu+yXb+PiUBqr4lAao+yXb+vl2Kq74lAaq+yXb+vl2Kq74lAaq+yXb+Pl2Kq74lAao+yXb+Pl2Kq75diqs+yXb+viUBqj5diqs+yXb+viUBqr5diqs+yXb+PiUBqr5diqs+yXb+PiUBqj4lAaq+yXb+vl2Kqz4lAao+yXb+vl2Kqz4lAao+yXb+Pl2Kqz4lAaq+yXb+Pl2Kqz4lAaq+AAAAPyUBqr4lAaq+AAAAPyUBqj4lAao+AAAAPyUBqj4lAao+AAAAPyUBqr4lAao+AAAAvyUBqr4lAao+AAAAvyUBqj4lAaq+AAAAvyUBqj4lAaq+AAAAvyUBqr4AAAAAurgtv7cIPL8AAAAAurgtv7cIPL8AAAAAurgtv7cIPL8AAAAAurgtv7cIPL8AAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAID3BDU/AAAAAPcENT/3BDU/AAAAAPcENT/3BDU/AAAAAPcENT/3BDU/AAAAAPcENT+3CDy/urgtvwAAAIC3CDy/urgtvwAAAIC3CDy/urgtvwAAAIC3CDy/urgtvwAAAIC3CDw/urgtvwAAAAC3CDw/urgtvwAAAAC3CDw/urgtvwAAAAC3CDw/urgtvwAAAAAAAAAAaM0Tv9EFUT8AAAAAaM0Tv9EFUT8AAAAAaM0Tv9EFUT8AAAAAaM0Tv9EFUT8AAAAAurgtv7cIPD8AAAAAurgtv7cIPD8AAAAAurgtv7cIPD8AAAAAurgtv7cIPD8AAAAAurgtP7cIPL8AAAAAurgtP7cIPL8AAAAAurgtP7cIPL8AAAAAurgtP7cIPL/RBVG/aM0TvwAAAIDRBVG/aM0TvwAAAIDRBVG/aM0TvwAAAIDRBVG/aM0TvwAAAIDRBVE/aM0TvwAAAADRBVE/aM0TvwAAAADRBVE/aM0TvwAAAADRBVE/aM0TvwAAAAAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIC3CDy/urgtPwAAAAC3CDy/urgtPwAAAAC3CDy/urgtPwAAAAC3CDy/urgtPwAAAAC3CDw/urgtPwAAAAC3CDw/urgtPwAAAAC3CDw/urgtPwAAAAC3CDw/urgtPwAAAAAAAAAAaM0Tv9EFUb8AAAAAaM0Tv9EFUb8AAAAAaM0Tv9EFUb8AAAAAaM0Tv9EFUb/3BDU/AAAAAPcENb/3BDU/AAAAAPcENb/3BDU/AAAAAPcENb/3BDU/AAAAAPcENb8AAAAAaM0TP9EFUT8AAAAAaM0TP9EFUT8AAAAAaM0TP9EFUT8AAAAAaM0TP9EFUT8AAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAACAurgtP7cIPD8AAACAurgtP7cIPD8AAACAurgtP7cIPD8AAACAurgtP7cIPD/3BDW/AAAAAPcENb/3BDW/AAAAAPcENb/3BDW/AAAAAPcENb/3BDW/AAAAAPcENb/RBVE/aM0TPwAAAIDRBVE/aM0TPwAAAIDRBVE/aM0TPwAAAIDRBVE/aM0TPwAAAIDRBVG/aM0TPwAAAADRBVG/aM0TPwAAAADRBVG/aM0TPwAAAADRBVG/aM0TPwAAAAAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAID3BDW/AAAAAPcENT/3BDW/AAAAAPcENT/3BDW/AAAAAPcENT/3BDW/AAAAAPcENT8AAAAAaM0TP9EFUb8AAAAAaM0TP9EFUb8AAAAAaM0TP9EFUb8AAAAAaM0TP9EFUb+9//++GAU1v73//769//++GAU1v73//769//++GAU1v73//769//++GAU1v73//769//8+GAU1v73//769//8+GAU1v73//769//8+GAU1v73//769//8+GAU1v73//769//8+GAU1v73//z69//8+GAU1v73//z69//8+GAU1v73//z69//8+GAU1v73//z69//++GAU1v73//z69//++GAU1v73//z69//++GAU1v73//z69//++GAU1v73//z69//++GAU1P73//769//++GAU1P73//769//++GAU1P73//769//++GAU1P73//769//8+GAU1P73//769//8+GAU1P73//769//8+GAU1P73//769//8+GAU1P73//769//8+GAU1P73//z69//8+GAU1P73//z69//8+GAU1P73//z69//8+GAU1P73//z69//++GAU1P73//z69//++GAU1P73//z69//++GAU1P73//z69//++GAU1P73//z4/xvQ+lJ88vz/G9D4/xvQ+lJ88vz/G9D4/xvQ+lJ88vz/G9D4/xvQ+lJ88vz/G9D4/xvS+lJ88vz/G9D4/xvS+lJ88vz/G9D4/xvS+lJ88vz/G9D4/xvS+lJ88vz/G9D4/xvS+lJ88vz/G9L4/xvS+lJ88vz/G9L4/xvS+lJ88vz/G9L4/xvS+lJ88vz/G9L4/xvQ+lJ88vz/G9L4/xvQ+lJ88vz/G9L4/xvQ+lJ88vz/G9L4/xvQ+lJ88vz/G9L4/xvQ+lJ88Pz/G9D4/xvQ+lJ88Pz/G9D4/xvQ+lJ88Pz/G9D4/xvQ+lJ88Pz/G9D4/xvS+lJ88Pz/G9D4/xvS+lJ88Pz/G9D4/xvS+lJ88Pz/G9D4/xvS+lJ88Pz/G9D4/xvS+lJ88Pz/G9L4/xvS+lJ88Pz/G9L4/xvS+lJ88Pz/G9L4/xvS+lJ88Pz/G9L4/xvQ+lJ88Pz/G9L4/xvQ+lJ88Pz/G9L4/xvQ+lJ88Pz/G9L4/xvQ+lJ88Pz/G9L4AAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAACAAAAAgAAAgL8AAACAAAAAgAAAgL8AAACAAAAAgAAAgL8AAACAAAAAgAAAgL8AAAAA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UABUAFUAVgBVAFYAVwBWAFcAVABYAFkAWgBZAFoAWwBaAFsAWABcAF0AXgBdAF4AXwBeAF8AXAAAAAEAAgABAAIAAwACAAMAAAAEAAUABgAFAAYABwAGAAcABAAIAAkACgAJAAoACwAKAAsACAAMAA0ADgANAA4ADwAOAA8ADAAQABEAEgARABIAEwASABMAEAAUABUAFgAVABYAFwAWABcAFAAYABkAGgAZABoAGwAaABsAGAAcAB0AHgAdAB4AHwAeAB8AHAAgACEAIgAhACIAIwAiACMAIAAkACUAJgAlACYAJwAmACcAJAAoACkAKgApACoAKwAqACsAKAAsAC0ALgAtAC4ALwAuAC8ALAAwADEAMgAxADIAMwAyADMAMAA0ADUANgA1ADYANwA2ADcANAA4ADkAOgA5ADoAOwA6ADsAOAA8AD0APgA9AD4APwA+AD8APABAAEEAQgBBAEIAQwBCAEMAQABEAEUARgBFAEYARwBGAEcARABIAEkASgBJAEoASwBKAEsASABMAE0ATgBNAE4ATwBOAE8ATABQAFEAUgBRAFIAUwBSAFMAUABUAFUAVgBVAFYAVwBWAFcAVABYAFkAWgBZAFoAWwBaAFsAWABcAF0AXgBdAF4AXwBeAF8AXABgAGEAYgBhAGIAYwBiAGMAYABkAGUAZgBlAGYAZwBmAGcAZABoAGkAagBpAGoAawBqAGsAaABsAG0AbgBtAG4AbwBuAG8AbABwAHEAcgBxAHIAcwByAHMAcAB0AHUAdgB1AHYAdwB2AHcAdAB4AHkAegB5AHoAewB6AHsAeAB8AH0AfgB9AH4AfwB+AH8AfACAAIEAggCBAIIAgwCCAIMAgACEAIUAhgCFAIYAhwCGAIcAhACIAIkAigCJAIoAiwCKAIsAiACMAI0AjgCNAI4AjwCOAI8AjACQAJEAkgCRAJIAkwCSAJMAkACUAJUAlgCVAJYAlwCWAJcAlACYAJkAmgCZAJoAmwCaAJsAmACcAJ0AngCdAJ4AnwCeAJ8AnAApACgAQwAoAEMAQgBDAEIAKQAFAAQAKwAEACsAKgArACoABQBVAFQABwBUAAcABgAHAAYAVQBBAEAAVwBAAFcAVgBXAFYAQQCgAKEAogChAKIAowCiAKMAoACkAKUApgClAKYApwCmAKcApACoAKkAqgCpAKoAqwCqAKsAqACsAK0ArgCtAK4ArwCuAK8ArACwALEAsgCxALIAswCyALMAsAC0ALUAtgC1ALYAtwC2ALcAtAC4ALAAswCwALMAuQCzALkAuAC6ALQAtwC0ALcAuwC3ALsAugC8ALgAuQC4ALkAvQC5AL0AvACxALoAuwC6ALsAsgC7ALIAsQC+ALwAvQC8AL0AvwC9AL8AvgC1AL4AvwC+AL8AtgC/ALYAtQDAAMEAwgDBAMIAwwDCAMMAwADEAMUAxgDFAMYAxwDGAMcAxADIAMkAygDJAMoAywDKAMsAyADMAM0AzgDNAM4AzwDOAM8AzADQANEA0gDRANIA0wDSANMA0ADUANUA1gDVANYA1wDWANcA1ADYANkA2gDZANoA2wDaANsA2ADcAN0A3gDdAN4A3wDeAN8A3AA="}]} diff --git a/Specs/Data/Models/PBR/BoxInterleaved/BoxInterleaved.gltf b/Specs/Data/Models/PBR/BoxInterleaved/BoxInterleaved.gltf new file mode 100644 index 000000000000..48f80e9466b0 --- /dev/null +++ b/Specs/Data/Models/PBR/BoxInterleaved/BoxInterleaved.gltf @@ -0,0 +1,140 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 12, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.800000011920929, + 0.0, + 0.0, + 1.0 + ] + } + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 24, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 648, + "uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAvwAAAL8AAAA/AAAAAAAAAAAAAIA/AAAAPwAAAL8AAAA/AAAAAAAAAAAAAIA/AAAAvwAAAD8AAAA/AAAAAAAAAAAAAIA/AAAAPwAAAD8AAAA/AAAAAAAAgL8AAAAAAAAAPwAAAL8AAAA/AAAAAAAAgL8AAAAAAAAAvwAAAL8AAAA/AAAAAAAAgL8AAAAAAAAAPwAAAL8AAAC/AAAAAAAAgL8AAAAAAAAAvwAAAL8AAAC/AACAPwAAAAAAAAAAAAAAPwAAAD8AAAA/AACAPwAAAAAAAAAAAAAAPwAAAL8AAAA/AACAPwAAAAAAAAAAAAAAPwAAAD8AAAC/AACAPwAAAAAAAAAAAAAAPwAAAL8AAAC/AAAAAAAAgD8AAAAAAAAAvwAAAD8AAAA/AAAAAAAAgD8AAAAAAAAAPwAAAD8AAAA/AAAAAAAAgD8AAAAAAAAAvwAAAD8AAAC/AAAAAAAAgD8AAAAAAAAAPwAAAD8AAAC/AACAvwAAAAAAAAAAAAAAvwAAAL8AAAA/AACAvwAAAAAAAAAAAAAAvwAAAD8AAAA/AACAvwAAAAAAAAAAAAAAvwAAAL8AAAC/AACAvwAAAAAAAAAAAAAAvwAAAD8AAAC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAC/AAAAAAAAAAAAAIC/AAAAvwAAAD8AAAC/AAAAAAAAAAAAAIC/AAAAPwAAAL8AAAC/AAAAAAAAAAAAAIC/AAAAPwAAAD8AAAC/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA" + } + ] +} diff --git a/Specs/Data/Models/PBR/RiggedSimple/RiggedSimple.gltf b/Specs/Data/Models/PBR/RiggedSimple/RiggedSimple.gltf new file mode 100644 index 000000000000..2abd36b3da55 --- /dev/null +++ b/Specs/Data/Models/PBR/RiggedSimple/RiggedSimple.gltf @@ -0,0 +1 @@ +{"asset":{"generator":"COLLADA2GLTF","version":"2.0"},"scene":0,"scenes":[{"nodes":[0]}],"nodes":[{"children":[4,1],"matrix":[1,0,0,0,0,0,-1,0,0,1,0,0,0,0,0,1]},{"mesh":0,"skin":0},{"children":[3],"translation":[0,-3.156060017772689e-7,-4.1803297996521],"rotation":[-0.7047404050827026,0,0,-0.7094652056694031],"scale":[1,0.9999998807907104,0.9999998807907104]},{"translation":[0,4.18717098236084,0],"rotation":[-0.0020521103870123625,-9.94789530750495e-8,-0.00029137087403796613,-0.999997854232788],"scale":[1,1,1.0000001192092896]},{"children":[2]}],"meshes":[{"primitives":[{"attributes":{"JOINTS_0":1,"NORMAL":2,"POSITION":3,"WEIGHTS_0":4},"indices":0,"mode":4,"material":0}],"name":"Cylinder"}],"animations":[{"channels":[{"sampler":0,"target":{"node":2,"path":"translation"}},{"sampler":1,"target":{"node":2,"path":"rotation"}},{"sampler":2,"target":{"node":2,"path":"scale"}}],"samplers":[{"input":5,"interpolation":"LINEAR","output":6},{"input":5,"interpolation":"LINEAR","output":7},{"input":5,"interpolation":"LINEAR","output":8}]},{"channels":[{"sampler":0,"target":{"node":3,"path":"translation"}},{"sampler":1,"target":{"node":3,"path":"rotation"}},{"sampler":2,"target":{"node":3,"path":"scale"}}],"samplers":[{"input":9,"interpolation":"LINEAR","output":10},{"input":9,"interpolation":"LINEAR","output":11},{"input":9,"interpolation":"LINEAR","output":12}]}],"skins":[{"inverseBindMatrices":13,"skeleton":2,"joints":[2,3],"name":"Armature"}],"accessors":[{"bufferView":0,"byteOffset":0,"componentType":5123,"count":564,"max":[95],"min":[0],"type":"SCALAR"},{"bufferView":1,"byteOffset":0,"componentType":5123,"count":96,"max":[1,1,0,0],"min":[0,0,0,0],"type":"VEC4"},{"bufferView":2,"byteOffset":0,"componentType":5126,"count":96,"max":[0.998198390007019,0.998198390007019,0.6888381242752075],"min":[-0.998198390007019,-0.998198390007019,-0.644473135471344],"type":"VEC3"},{"bufferView":2,"byteOffset":1152,"componentType":5126,"count":96,"max":[1,1,4.575077056884766],"min":[-1,-0.9999995827674866,-4.575077056884766],"type":"VEC3"},{"bufferView":3,"byteOffset":0,"componentType":5126,"count":96,"max":[1,0.261398196220398,0,0],"min":[0.738601803779602,0,0,0],"type":"VEC4"},{"bufferView":4,"byteOffset":0,"componentType":5126,"count":3,"max":[2.083333015441895],"min":[0.04166661947965622],"type":"SCALAR"},{"bufferView":5,"byteOffset":0,"componentType":5126,"count":3,"max":[0,-3.156060017772689e-7,-4.1803297996521],"min":[0,-3.156060017772689e-7,-4.1803297996521],"type":"VEC3"},{"bufferView":6,"byteOffset":0,"componentType":5126,"count":3,"max":[-0.7047404050827026,0,0,-0.7094652056694031],"min":[-0.7047404050827026,0,0,-0.7094652056694031],"type":"VEC4"},{"bufferView":5,"byteOffset":36,"componentType":5126,"count":3,"max":[1,0.9999998807907104,0.9999998807907104],"min":[1,0.9999998807907104,0.9999998807907104],"type":"VEC3"},{"bufferView":4,"byteOffset":12,"componentType":5126,"count":3,"max":[2.083333015441895],"min":[0.04166661947965622],"type":"SCALAR"},{"bufferView":5,"byteOffset":72,"componentType":5126,"count":3,"max":[0,4.18717098236084,0],"min":[0,4.18717098236084,0],"type":"VEC3"},{"bufferView":6,"byteOffset":48,"componentType":5126,"count":3,"max":[0.2933785021305084,-9.94789530750495e-8,-0.0002783441450446844,-0.9559963345527648],"min":[-0.0020521103870123625,-0.00008614854596089572,-0.00029137087403796613,-0.999997854232788],"type":"VEC4"},{"bufferView":5,"byteOffset":108,"componentType":5126,"count":3,"max":[1,1,1.0000001192092896],"min":[1,1,1.0000001192092896],"type":"VEC3"},{"bufferView":7,"byteOffset":0,"componentType":5126,"count":2,"max":[1,0,0.000001394809942212305,0,0.000002896920022976701,0.006681859027594328,-0.9999778270721436,0,0.0005827349959872663,0.9999966025352478,0.006681739818304777,0,0,4.18023681640625,0.02795993909239769,1],"min":[0.9999999403953552,-0.0005827400018461049,0,0,0,0.002577662002295256,-0.9999967217445374,0,0,0.999977707862854,0.002577601931989193,0,-0.000004012620138382772,-0.006818830035626888,0.027931740507483482,1],"type":"MAT4"}],"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[0.27963539958000183,0.6399999856948853,0.21094390749931335,1],"metallicFactor":0},"emissiveFactor":[0,0,0],"name":"Material_001-effect"}],"bufferViews":[{"buffer":0,"byteOffset":5000,"byteLength":1128,"target":34963},{"buffer":0,"byteOffset":4208,"byteLength":768,"byteStride":8,"target":34962},{"buffer":0,"byteOffset":1904,"byteLength":2304,"byteStride":12,"target":34962},{"buffer":0,"byteOffset":224,"byteLength":1536,"byteStride":16,"target":34962},{"buffer":0,"byteOffset":4976,"byteLength":24},{"buffer":0,"byteOffset":1760,"byteLength":144},{"buffer":0,"byteOffset":128,"byteLength":96},{"buffer":0,"byteOffset":0,"byteLength":128}],"buffers":[{"byteLength":6128,"uri":"data:application/octet-stream;base64,AACAPwAAAAAAAAAAAAAAAAAAAAB/89o7jP5/vwAAAAAAAAAAiv5/P3/y2jsAAAAAAAAAAIDEhUAb0eQ8AACAP///fz8Fwxi6TjW7NQAAAAC1aEI2/u0oO8n/f78AAAAAr8IYOsf/fz/87Cg7AAAAACWkhrZ+cN+7PgzlPAAAgD/eaTS/AAAAgAAAAICDnzW/3mk0vwAAAIAAAACAg581v95pNL8AAACAAAAAgIOfNb+zfAa7IqHVsyPDmLnc/3+/tTWWPqaqtLi47pG5Lbx0v7N8BrsiodWzI8OYudz/f78AAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAIVPT/81YU+AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAhU9P/zVhT4AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAACFT0//NWFPgAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAIVPT/81YU+AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAABBU9P/zVhT4AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAEFT0//NWFPgAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAIVPT/81YU+AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAhU9P/zVhT4AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAACFT0//NWFPgAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAIVPT/81YU+AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAABBU9P/zVhT4AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAACFT0//NWFPgAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAIVPT/81YU+AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAhU9P/zVhT4AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAACFT0//NWFPgAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAIVPT/81YU+AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAhU9P/zVhT4AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAACFT0//NWFPgAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAIVPT/81YU+AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAhU9P/zVhT4AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAACFT0//NWFPgAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAQVPT/81YU+AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAhU9P/zVhT4AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAACFT0//NWFPgAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAIVPT/81YU+AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAhU9P/zVhT4AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAhU9P/zVhT4AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAEFT0//NWFPgAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAIVPT/81YU+AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAhU9P/zVhT4AAAAAAAAAAAQVPT/81YU+AAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAABBU9P/zVhT4AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAAAAj3CptEPFhcAAAAAAj3CptEPFhcAAAAAAj3CptEPFhcAAAIA/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AgACAAEABAAEAAMABgAGAAUACAAIAAcACgAKAAkADAAMAAsADgAOAA0AEAAQAA8AEgASABEAFAAUABMAFgAWABUAGAAYABcAGgAaABkAHAAcABsAHgAeAB0AIAAgAB8AIgAiACEAJAAkACMAJgAmACUAKAAoACcAKgAqACkALAAsACsALgAuAC0AMAAyADAAMQA0ADIAMwBGADQANQBGADUANwA3ADYAOQA5ADgAOwADAAEAAAAAADwAAwA6ADgANgA2ADUAMwAzADEALwAvAC0AMwArACkAJwAnACUAIwAjACEAHwAfAB0AGwAbABkAFwAXABUAEwATABEADwAPAA0AEwALAAkABwAHAAUAAwADADwAOgA6ADYAMwAzAC0AKwArACcAIwAjAB8AEwAbABcAEwATAA0ACwALAAcAAwADADoAMwAzACsAIwAfABsAEwATAAsAAwADADMAEwA+ADwAPQA7ADoAPgBCAEMAXwBfAF4AXQBdAFwAWwBbAFoAQQBBAFkAWABYAFcAQQBWAFUAPwBUAFMAPwA/AFIATwBRAFAATwBPAE4ATQBNAEwAQABAAEsASgBKAEkAQABIAEcARQBFAEQAQgBCAF8AQQBdAFsAQQBBAFcAVgBVAFQAPwBSAFEATwBPAE0AQABAAEkASABIAEUAQABfAF0AQQBBAFYAPwA/AE8AQABAAEUAQgBCAEEAQABEADsAQgBCAD4AQwBFADkARABHADcARQBIAEYARwBJADQASABKADIASQBLADAASgBAAC4ASwBMACwAQABNACoATABOACgATQBPACYATgBQACQATwBRACIAUABSACAAUQA/AB4AUgBTABwAPwBUABoAUwBVABgAVABWABYAVQBXABQAVgBYABIAVwBZABAAWABBAA4AWQBaAAwAQQBbAAoAWgBcAAgAWwBdAAYAXABeAAQAXQBfAAIAXgBDAD0AXwA="}]} diff --git a/Specs/Data/Models/PBR/TwoSidedPlane/TwoSidedPlane.gltf b/Specs/Data/Models/PBR/TwoSidedPlane/TwoSidedPlane.gltf new file mode 100644 index 000000000000..eded55f464c1 --- /dev/null +++ b/Specs/Data/Models/PBR/TwoSidedPlane/TwoSidedPlane.gltf @@ -0,0 +1 @@ +{"accessors":[{"bufferView":0,"byteOffset":0,"componentType":5123,"count":6,"max":[5],"min":[0],"type":"SCALAR"},{"bufferView":1,"byteOffset":0,"componentType":5126,"count":6,"max":[1,0,1],"min":[-1,0,-1],"type":"VEC3"},{"bufferView":2,"byteOffset":0,"componentType":5126,"count":6,"max":[0,1,0],"min":[0,1,0],"type":"VEC3"},{"bufferView":3,"byteOffset":0,"componentType":5126,"count":6,"max":[0,0,-1,1],"min":[0,0,-1,1],"type":"VEC4"},{"bufferView":4,"byteOffset":0,"componentType":5126,"count":6,"max":[0.9999,0.9999],"min":[0.0001,0.0001],"type":"VEC2"}],"asset":{"generator":"VKTS glTF 2.0 exporter","version":"2.0"},"bufferViews":[{"buffer":0,"byteLength":12,"byteOffset":0,"target":34963},{"buffer":0,"byteLength":72,"byteOffset":12,"target":34962},{"buffer":0,"byteLength":72,"byteOffset":84,"target":34962},{"buffer":0,"byteLength":96,"byteOffset":156,"target":34962},{"buffer":0,"byteLength":48,"byteOffset":252,"target":34962}],"buffers":[{"byteLength":300,"uri":"data:application/octet-stream;base64,AAABAAIAAwAEAAUAAACAPwAAAAAAAIA/AACAvwAAAAAAAIC/AACAvwAAAAAAAIA/AACAPwAAAAAAAIA/AACAPwAAAAAAAIC/AACAvwAAAAAAAIC/AAAAgAAAgD8AAACAAAAAgAAAgD8AAACAAAAAgAAAgD8AAACAAAAAgAAAgD8AAACAAAAAgAAAgD8AAACAAAAAgAAAgD8AAACAAAAAAAAAAAAAAIC/AACAPwAAAAAAAAAAAACAvwAAgD8AAAAAAAAAAAAAgL8AAIA/AAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAACAvwAAgD8AAAAAAAAAAAAAgL8AAIA/F7fROBe30Thy+X8/cvl/Pxe30Thy+X8/F7fROBe30Thy+X8/F7fROHL5fz9y+X8/"}],"images":[],"materials":[{"doubleSided":true,"name":"TwoSidedPlane","pbrMetallicRoughness":{"baseColorFactor":[0.5,0.5,0.5,1],"metallicFactor":0.5,"roughnessFactor":0.5}}],"meshes":[{"name":"TwoSidedPlane","primitives":[{"attributes":{"NORMAL":2,"POSITION":1,"TANGENT":3,"TEXCOORD_0":4},"indices":0,"material":0,"mode":4}]}],"nodes":[{"mesh":0,"name":"TwoSidedPlane"}],"samplers":[{}],"scene":0,"scenes":[{"nodes":[0]}],"textures":[]} diff --git a/Specs/Scene/ModelSpec.js b/Specs/Scene/ModelSpec.js index c7dd2dfec270..09d688f24856 100644 --- a/Specs/Scene/ModelSpec.js +++ b/Specs/Scene/ModelSpec.js @@ -96,7 +96,6 @@ defineSuite([ var animBoxesUrl = './Data/Models/anim-test-1-boxes/anim-test-1-boxes.gltf'; var riggedFigureUrl = './Data/Models/rigged-figure-test/rigged-figure-test.gltf'; var riggedSimpleUrl = './Data/Models/rigged-simple/rigged-simple.gltf'; - var boxConstantUrl = './Data/Models/MaterialsCommon/BoxConstant.gltf'; var boxLambertUrl = './Data/Models/MaterialsCommon/BoxLambert.gltf'; var boxBlinnUrl = './Data/Models/MaterialsCommon/BoxBlinn.gltf'; @@ -108,6 +107,7 @@ defineSuite([ var boxSpotLightUrl = './Data/Models/MaterialsCommon/BoxSpotLight.gltf'; var boxTransparentUrl = './Data/Models/MaterialsCommon/BoxTransparent.gltf'; var boxColorUrl = './Data/Models/Box-Color/Box-Color.gltf'; + var boxUint32Indices = './Data/Models/Box-Uint32Indices/Box-Uint32Indices.gltf'; var boxQuantizedUrl = './Data/Models/WEB3DQuantizedAttributes/Box-Quantized.gltf'; var boxColorQuantizedUrl = './Data/Models/WEB3DQuantizedAttributes/Box-Color-Quantized.gltf'; var boxScalarQuantizedUrl = './Data/Models/WEB3DQuantizedAttributes/Box-Scalar-Quantized.gltf'; @@ -117,6 +117,14 @@ defineSuite([ var riggedSimpleQuantizedUrl = './Data/Models/WEB3DQuantizedAttributes/RiggedSimple-Quantized.gltf'; var CesiumManUrl = './Data/Models/MaterialsCommon/Cesium_Man.gltf'; + var boomBoxUrl = './Data/Models/PBR/BoomBox/BoomBox.gltf'; + var boxPbrUrl = './Data/Models/PBR/Box/Box.gltf'; + var boxAnimatedPbrUrl = './Data/Models/PBR/BoxAnimated/BoxAnimated.gltf'; + var boxInterleavedPbrUrl = './Data/Models/PBR/BoxInterleaved/BoxInterleaved.gltf'; + var riggedSimplePbrUrl = './Data/Models/PBR/RiggedSimple/RiggedSimple.gltf'; + var animatedMorphCubeUrl = './Data/Models/PBR/AnimatedMorphCube/AnimatedMorphCube.gltf'; + var twoSidedPlaneUrl = './Data/Models/PBR/TwoSidedPlane/TwoSidedPlane.gltf'; + var texturedBoxModel; var cesiumAirModel; var animBoxesModel; @@ -422,7 +430,7 @@ defineSuite([ it('rejects readyPromise on error', function() { var invalidGltf = clone(texturedBoxModel.gltf, true); - invalidGltf.shaders.CesiumTexturedBoxTest0FS.uri = 'invalid.glsl'; + invalidGltf.shaders[0].uri = 'invalid.glsl'; var model = primitives.add(new Model({ gltf : invalidGltf @@ -440,7 +448,7 @@ defineSuite([ it('rejects readyPromise on error', function() { var invalidGltf = clone(texturedBoxModel.gltf, true); - invalidGltf.shaders.CesiumTexturedBoxTest0FS.uri = 'invalid.glsl'; + invalidGltf.shaders[0].uri = 'invalid.glsl'; var model = primitives.add(new Model({ gltf : invalidGltf @@ -481,15 +489,6 @@ defineSuite([ factor : 0.0, units : 0.0 }, - scissorTest : { - enabled : false, - rectangle : { - x : 0.0, - y : 0.0, - width : 0.0, - height : 0.0 - } - }, depthRange : { near : 0.0, far : 1.0 @@ -614,7 +613,7 @@ defineSuite([ var node = texturedBoxModel.getNode('Mesh'); expect(node).toBeDefined(); expect(node.name).toEqual('Mesh'); - expect(node.id).toEqual('Geometry-mesh002Node'); + expect(node.id).toEqual(0); expect(node.show).toEqual(true); // Change node transform and render @@ -650,7 +649,7 @@ defineSuite([ var mesh = texturedBoxModel.getMesh('Mesh'); expect(mesh).toBeDefined(); expect(mesh.name).toEqual('Mesh'); - expect(mesh.id).toEqual('Geometry-mesh002'); + expect(mesh.id).toEqual(0); expect(mesh.materials[0].name).toEqual('Texture'); }); @@ -675,7 +674,7 @@ defineSuite([ var material = texturedBoxModel.getMaterial('Texture'); expect(material).toBeDefined(); expect(material.name).toEqual('Texture'); - expect(material.id).toEqual('Effect-Texture'); + expect(material.id).toEqual(0); }); it('ModelMaterial.setValue throws when name is not provided', function() { @@ -771,7 +770,7 @@ defineSuite([ it('Throws because of invalid extension', function() { return loadJson(boxUrl).then(function(gltf) { - gltf.extensionsUsed = ['NOT_supported_extension']; + gltf.extensionsRequired = ['NOT_supported_extension']; var model = primitives.add(new Model({ gltf : gltf })); @@ -785,7 +784,7 @@ defineSuite([ it('Throws because of invalid extension', function() { return loadJson(boxUrl).then(function(gltf) { - gltf.extensionsUsed = ['CESIUM_binary_glTF']; + gltf.extensionsRequired = ['CESIUM_binary_glTF']; var model = primitives.add(new Model({ gltf : gltf })); @@ -801,12 +800,12 @@ defineSuite([ return loadModel(cesiumAir_0_8Url, { minimumPixelSize : 1 }).then(function(m) { - // 0.8 models had a number version. Verify it is converted to a string. - expect(m.gltf.asset.version).toEqual('0.8'); + // Verify that the version has been updated + expect(m.gltf.asset.version).toEqual('2.0'); // Verify that rotation is converted from // Axis-Angle (1,0,0,0) to Quaternion (0,0,0,1) - var rotation = m.gltf.nodes['Geometry-mesh005Node'].rotation; + var rotation = m.gltf.nodes[3].rotation; expect(rotation).toEqual([0.0, 0.0, 0.0, 1.0]); verifyRender(m); @@ -861,7 +860,7 @@ defineSuite([ }); it('Throws because of an invalid Binary glTF header - magic', function() { - var arrayBuffer = new ArrayBuffer(16); + var arrayBuffer = new ArrayBuffer(20); expect(function() { return new Model({ gltf : arrayBuffer @@ -870,7 +869,7 @@ defineSuite([ }); it('Throws because of an invalid Binary glTF header - version', function() { - var arrayBuffer = new ArrayBuffer(16); + var arrayBuffer = new ArrayBuffer(20); var bytes = new Uint8Array(arrayBuffer); bytes[0] = 'g'.charCodeAt(0); bytes[1] = 'l'.charCodeAt(0); @@ -1136,10 +1135,10 @@ defineSuite([ var spyAdd = jasmine.createSpy('listener'); animations.animationAdded.addEventListener(spyAdd); var a = animations.add({ - name : 'animation_1' + name : 1 }); expect(a).toBeDefined(); - expect(a.name).toEqual('animation_1'); + expect(a.name).toEqual(1); expect(a.startTime).not.toBeDefined(); expect(a.delay).toEqual(0.0); expect(a.stopTime).not.toBeDefined(); @@ -1208,7 +1207,7 @@ defineSuite([ var time = JulianDate.fromDate(new Date('January 1, 2014 12:00:00 UTC')); var animations = animBoxesModel.activeAnimations; var a = animations.add({ - name : 'animation_1', + name : 1, startTime : time, removeOnStop : true }); @@ -1254,7 +1253,7 @@ defineSuite([ var animations = animBoxesModel.activeAnimations; var a = animations.add({ - name : 'animation_1', + name : 1, startTime : time, delay : 1.0 }); @@ -1278,7 +1277,7 @@ defineSuite([ var animations = animBoxesModel.activeAnimations; var a = animations.add({ - name : 'animation_1', + name : 1, startTime : time, stopTime : stopTime }); @@ -1302,7 +1301,7 @@ defineSuite([ var time = JulianDate.fromDate(new Date('January 1, 2014 12:00:00 UTC')); var animations = animBoxesModel.activeAnimations; var a = animations.add({ - name : 'animation_1', + name : 1, startTime : time, speedup : 1.5 }); @@ -1327,7 +1326,7 @@ defineSuite([ var time = JulianDate.fromDate(new Date('January 1, 2014 12:00:00 UTC')); var animations = animBoxesModel.activeAnimations; var a = animations.add({ - name : 'animation_1', + name : 1, startTime : time, reverse : true }); @@ -1354,7 +1353,7 @@ defineSuite([ var time = JulianDate.fromDate(new Date('January 1, 2014 12:00:00 UTC')); var animations = animBoxesModel.activeAnimations; var a = animations.add({ - name : 'animation_1', + name : 1, startTime : time, loop : ModelAnimationLoop.REPEAT }); @@ -1384,7 +1383,7 @@ defineSuite([ var time = JulianDate.fromDate(new Date('January 1, 2014 12:00:00 UTC')); var animations = animBoxesModel.activeAnimations; var a = animations.add({ - name : 'animation_1', + name : 1, startTime : time, loop : ModelAnimationLoop.MIRRORED_REPEAT }); @@ -1418,7 +1417,7 @@ defineSuite([ var time = JulianDate.fromDate(new Date('January 1, 2014 12:00:00 UTC')); var animations = m.activeAnimations; var a = animations.add({ - name : 'animation_1', + name : 1, startTime : time }); @@ -1765,7 +1764,7 @@ defineSuite([ loadedColor = rgba; }); - pollToPromise(function() { + return pollToPromise(function() { // Render scene to progressively load textures scene.renderForSpecs(); // Textures have finished loading @@ -1791,7 +1790,7 @@ defineSuite([ loadedColor = rgba; }); - pollToPromise(function() { + return pollToPromise(function() { // Render scene to progressively load textures (they should already be loaded) scene.renderForSpecs(); // Textures have finished loading @@ -1894,6 +1893,32 @@ defineSuite([ }); }); + it('loads a glTF with WEB3D_quantized_attributes and accessor.normalized', function() { + return loadModel(boxQuantizedUrl).then(function(m) { + verifyRender(m); + var gltf = m.gltf; + var accessors = gltf.accessors; + var normalAccessor = accessors[2]; + var positionAccessor = accessors[1]; + normalAccessor.normalized = true; + positionAccessor.normalized = true; + var decodeMatrixArray = normalAccessor.extensions.WEB3D_quantized_attributes.decodeMatrix; + var decodeMatrix = new Matrix4(); + Matrix4.unpack(decodeMatrixArray, 0, decodeMatrix); + Matrix4.multiplyByUniformScale(decodeMatrix, 65535.0, decodeMatrix); + Matrix4.pack(decodeMatrix, decodeMatrixArray); + decodeMatrixArray = positionAccessor.extensions.WEB3D_quantized_attributes.decodeMatrix; + Matrix4.unpack(decodeMatrixArray, 0, decodeMatrix); + Matrix4.multiplyByUniformScale(decodeMatrix, 65535.0, decodeMatrix); + Matrix4.pack(decodeMatrix, decodeMatrixArray); + primitives.remove(m); + return loadModelJson(gltf, {}).then(function(m) { + verifyRender(m); + primitives.remove(m); + }); + }); + }); + it('loads a glTF with WEB3D_quantized_attributes POSITION and NORMAL where primitives with different accessors use the same shader', function() { return loadModel(milkTruckQuantizedUrl).then(function(m) { verifyRender(m); @@ -1922,6 +1947,118 @@ defineSuite([ }); }); + it('loads a glTF 2.0 without textures', function() { + return loadModel(boxPbrUrl).then(function(m) { + verifyRender(m); + primitives.remove(m); + }); + }); + + it('loads a glTF 2.0 with textures', function() { + return loadModel(boomBoxUrl).then(function(m) { + m.scale = 20.0; // Source model is very small, so scale up a bit + verifyRender(m); + primitives.remove(m); + }); + }); + + it('loads a glTF 2.0 with node animation', function() { + return loadModel(boxAnimatedPbrUrl).then(function(m) { + verifyRender(m); + primitives.remove(m); + }); + }); + + it('loads a glTF 2.0 with skinning', function() { + return loadModel(riggedSimplePbrUrl).then(function(m) { + verifyRender(m); + primitives.remove(m); + }); + }); + + it('loads a glTF 2.0 with morph targets', function() { + return loadModel(animatedMorphCubeUrl).then(function(m) { + verifyRender(m); + primitives.remove(m); + }); + }); + + it('loads a glTF 2.0 with alphaMode set to OPAQUE', function() { + return loadJson(boxPbrUrl).then(function(gltf) { + gltf.materials[0].alphaMode = 'OPAQUE'; + + return loadModelJson(gltf).then(function(m) { + verifyRender(m); + primitives.remove(m); + }); + }); + }); + + it('loads a glTF 2.0 with alphaMode set to MASK', function() { + return loadJson(boxPbrUrl).then(function(gltf) { + gltf.materials[0].alphaMode = 'MASK'; + gltf.materials[0].alphaCutoff = 0.5; + + return loadModelJson(gltf).then(function(m) { + verifyRender(m); + primitives.remove(m); + }); + }); + }); + + it('loads a glTF 2.0 with alphaMode set to BLEND', function() { + return loadJson(boxPbrUrl).then(function(gltf) { + gltf.materials[0].alphaMode = 'BLEND'; + + return loadModelJson(gltf).then(function(m) { + verifyRender(m); + primitives.remove(m); + }); + }); + }); + + it('loads a glTF 2.0 with interleaved vertex attributes', function() { + return loadModel(boxInterleavedPbrUrl).then(function(m) { + verifyRender(m); + primitives.remove(m); + }); + }); + + function checkDoubleSided(model, doubleSided) { + var camera = scene.camera; + var center = Matrix4.multiplyByPoint(model.modelMatrix, model.boundingSphere.center, new Cartesian3()); + var range = 4.0 * model.boundingSphere.radius; + + camera.lookAt(center, new HeadingPitchRange(0, -CesiumMath.PI_OVER_TWO, range)); + expect(scene).notToRender([0, 0, 0, 255]); + camera.lookAt(center, new HeadingPitchRange(0, CesiumMath.PI_OVER_TWO, range)); + if (doubleSided) { + expect(scene).notToRender([0, 0, 0, 255]); + } else { + expect(scene).toRender([0, 0, 0, 255]); + } + } + + it('loads a glTF 2.0 with doubleSided set to false', function() { + return loadJson(twoSidedPlaneUrl).then(function(gltf) { + gltf.materials[0].doubleSided = false; + return loadModelJson(gltf).then(function(m) { + m.show = true; + checkDoubleSided(m, false); + primitives.remove(m); + }); + }); + }); + + + it('loads a glTF 2.0 with doubleSided set to true', function() { + return loadModel(twoSidedPlaneUrl).then(function(m) { + m.show = true; + checkDoubleSided(m, true); + primitives.remove(m); + }); + }); + function testBoxSideColors(m) { var rotateX = Matrix3.fromRotationX(CesiumMath.toRadians(90.0)); var rotateY = Matrix3.fromRotationY(CesiumMath.toRadians(90.0)); @@ -1953,7 +2090,7 @@ defineSuite([ } } - it('loads a gltf with color attributes', function() { + it('loads a gltf with normalized color attributes', function() { return loadModel(boxColorUrl).then(function(m) { expect(m.ready).toBe(true); expect(scene).toRender([0, 0, 0, 255]); @@ -1964,6 +2101,38 @@ defineSuite([ }); }); + it('loads a gltf with uint32 indices', function() { + var context = scene.context; + if (context._elementIndexUint) { + return loadModel(boxUint32Indices).then(function(m) { + verifyRender(m); + primitives.remove(m); + }); + } + }); + + it('throws runtime error when loading a gltf with uint32 indices if OES_element_index_uint is disabled', function() { + var context = scene.context; + var uint32Supported = context._elementIndexUint; + context._elementIndexUint = false; + + var model = primitives.add(Model.fromGltf({ + url : boxUint32Indices + })); + + return pollToPromise(function() { + // Render scene to progressively load the model + scene.renderForSpecs(); + return model.ready; + }, { timeout: 10000 }).then(function() { + fail('should not resolve'); + }).otherwise(function(e) { + expect(e).toBeDefined(); + primitives.remove(model); + context._elementIndexUint = uint32Supported; + }); + }); + it('loads a gltf with WEB3D_quantized_attributes COLOR', function() { return loadModel(boxColorQuantizedUrl).then(function(m) { expect(m.ready).toBe(true);