├── LICENSE ├── README.md ├── examples ├── ColoredLights.html ├── CornellBox.html ├── CornellBox_Textured.html ├── Mailbox.html ├── Sponza.html └── img │ ├── crate.jpg │ ├── multicol.jpg │ └── red.jpg ├── js ├── DDSLoader.js ├── LightBaking.js ├── LightBakingDemo.js ├── LightBakingWorker.js ├── Lucy100k_slim.js ├── MTLLoader.js ├── OBJLoader.js ├── OBJMTLLoader.js ├── Octree.js ├── Sidebar.LightBaking.js ├── TrackballControls.js ├── dat.gui.min.js ├── jszip-utils.js ├── jszip.min.js ├── packer.growing.js ├── r71 │ ├── three.js │ └── three.min.js ├── r93 │ ├── three.js │ └── three.min.js ├── three.js └── three.min.js └── obj └── sponza_01 ├── 00_skap.JPG ├── 01_STUB-bump.jpg ├── 01_STUB.JPG ├── 01_S_ba.JPG ├── 01_S_kap-bump.jpg ├── 01_S_kap.JPG ├── 01_St_kp-bump.jpg ├── 01_St_kp.JPG ├── KAMEN-bump.jpg ├── KAMEN-stup.JPG ├── KAMEN.JPG ├── copyright.txt ├── prozor1.JPG ├── reljef-bump.jpg ├── reljef.JPG ├── sp_luk-bump.JPG ├── sp_luk.JPG ├── sponza.mtl ├── sponza.obj ├── vrata_ko.JPG ├── vrata_kr.JPG ├── x01_st-bump.jpg └── x01_st.JPG /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015 Dominik Link, Jan Pascal Tschudy, FHNW. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LightBaking.js 2 | ======== 3 | 4 | #### Light Baking for three.js #### 5 | 6 | The aim of this project is to provide light baking functionality for [THREE.js WebGL library](http://mrdoob.github.com/three.js/). 7 | This project handles everything from UV mapping to baking the light for the whole scene with Path Tracing and filter the maps to get a smooth result even with lower resolution maps. 8 | 9 | edit: This is a fork by manthrax, attempting to get this running with current three.js 10 | 11 | ```html 12 | This build might not be stable for THREE.js 13 | ``` 14 | 15 | ## Features 16 | 17 | * Distortion free UV mapping 18 | * Optimizing UV layout with bin packing from [Code inComplete](http://codeincomplete.com/posts/2011/5/7/bin_packing/) 19 | * Light Baking 20 | * Path Tracing 21 | * Gauss/Box Filter 22 | * Import and Export 23 | * Integration in three.js 24 | * Integration in the [three.js editor](http://threejs.org/editor/) 25 | * Web Worker functionality 26 | 27 | ## Examples 28 | 29 | Live Examples: 30 | * [Cornell Box](https://cdn.rawgit.com/manthrax/lightbaking/master/examples/CornellBox.html) 31 | * [Cornell Box_Textured](https://cdn.rawgit.com/manthrax/lightbaking/master/examples/CornellBox_Textured.html) 32 | * [Colored Lights](https://cdn.rawgit.com/manthrax/lightbaking/master/examples/ColoredLights.html) 33 | * [Mailbox](https://cdn.rawgit.com/manthrax/lightbaking/master/examples/Mailbox.html) 34 | 35 | Pictures: 36 | * [Cornell Box](http://web.fhnw.ch/technik/projekte/i/bachelor15/tschudy-link/img/cornell_algorithm.png) 37 | * [Cornell Box Ball Lightmap](http://web.fhnw.ch/technik/projekte/i/bachelor15/tschudy-link/img/uvpacking.png) 38 | * [Cornell Box Textures](http://web.fhnw.ch/technik/projekte/i/bachelor15/tschudy-link/img/cornellbox_walltexture.png) 39 | * [Mailbox](http://web.fhnw.ch/technik/projekte/i/bachelor15/tschudy-link/img/mailbox.png) 40 | * [Editor integration](http://web.fhnw.ch/technik/projekte/i/bachelor15/tschudy-link/img/editor.png) 41 | * [Concave Object](http://web.fhnw.ch/technik/projekte/i/bachelor15/tschudy-link/img/concaveObj.png) 42 | 43 | 44 | ## Recommendations 45 | * Webserver eg node.js, phpstorm etc. 46 | * Chrome 44 (Mozilla and IE seems to have some issues while using our workers) 47 | 48 | ## Usage 49 | Download the following scripts: 50 | * Mandatory [script](https://github.com/manthrax/lightbaking/tree/master/js/LightBaking.js) 51 | * Optional only for using workers [script](https://github.com/manthrax/lightbaking/tree/master/js/LightBakingWorker.js) 52 | * Optional for import/export [script](https://github.com/Stuk/jszip/blob/master/dist/jszip.min.js) 53 | * Optional for import/export [script](https://github.com/Stuk/jszip-utils/tree/master/dist/jszip-utils.min.js) 54 | 55 | Include them in your html after the [THREE.js WebGL library](http://mrdoob.github.com/three.js/). 56 | 57 | ```html 58 | 59 | 60 | ``` 61 | 62 | #### Minimal Config (Singlethreaded) 63 | ```html 64 | lightBaking = THREE.LightBaking({ 65 | "scene"": scene, 66 | "appMode": THREE.LightBaking.ApplicationExecutionEnum.SINGLETHREADED 67 | )}; 68 | ``` 69 | 70 | #### Minimal Config (Multithreaded) 71 | ```html 72 | lightBaking = THREE.LightBaking({ 73 | "scene"": scene, 74 | "workerSource": "LightBakingWorker.js", //optional, only used if multithreading is enabled. Set the source of the LightBakingWorker.js file. 75 | )}; 76 | ``` 77 | 78 | #### Parameter description 79 | All Parameters are listed with their default values. 80 | 81 | ```html 82 | lightBaking = THREE.LightBaking( { 83 | 84 | // Scene Information 85 | // pass the scene object to the LightBaking plugin 86 | "scene"": scene 87 | 88 | // Application Execution Model 89 | // Runs the application in the desired mode. 90 | // - SINGLETHREADED: Everything is done in the main(ui)thread 91 | // - ASYNC: Executed asynchronously(not really different to SINGLETHREADED) 92 | // - MULTITHREADED: Using dedicated WebWorkers 93 | "appMode": THREE.LightBaking.ApplicationExecutionEnum.MULTITHREADED, 94 | 95 | // (dedicated) Web Worker 96 | // - workerSource: only used if multithreading is enabled. Set the source of the LightBakingWorker.js file. 97 | // - workerLimit: Maximal amount of worker 98 | "workerSource": "js/LightBakingWorker.js", 99 | "workerLimit": navigator.hardwareConcurrency, 100 | 101 | // Debugging 102 | // only used for developing purposes 103 | // - debugText: get some insight which method was called 104 | // - debugLightmap: same functionality as debugLightmaps() on THREE.LightBaking 105 | "debugText": false, 106 | "debugLightmap": false, 107 | "debugVisual": false, 108 | "debugVisualMeshNbr": 0, 109 | "debugVisualProbabilityFilter": 0.005, 110 | "debugVisualIsSelectedMesh": false 111 | "debugVisualRT": false, 112 | 113 | // Lightmap size 114 | // Usually 2^x 115 | "textureWidth": 512, 116 | "textureHeight": 512, 117 | 118 | // Shading Techniques 119 | // - PHONG 120 | // - FLAT 121 | // - FLATFAST (color determined by face vertices, and the whole face gets this color) 122 | "shading": THREE.LightBaking.ShadingEnum.PHONG, 123 | 124 | // Illumination Models 125 | // Only Lambertian. Phong doesn't make sense in terms of lightbaking. 126 | // - LAMBERT 127 | "illuminationModel": THREE.LightBaking.IlluminationModelEnum.LAMBERT, 128 | 129 | // UV related 130 | // - uvMethod: optional, 0 - first try, 1 - simple centered, 2 - bin packing approach 131 | // - packingOffset: optional, offset in pixels for the UV map 132 | // - uvSmoothing: optional, offset in percent for the inTriangle test used in baking 133 | "uvMethod": THREE.LightBaking.UVMethodEnum.PACKED, 134 | "packingOffset": 2, 135 | "uvSmoothing": 0.2, 136 | 137 | // Light Baking algorithms 138 | // used for baking TWOPASS/PATHTRACING 139 | "bakingMethod": THREE.LightBaking.BakingMethodEnum.PATHTRACING, 140 | 141 | // TwoPass Method 142 | // - twoPassCount: 1 - only direct light, 2 with indirect light 143 | // (more passes not possible) 144 | "twoPassPassCount": 2, 145 | 146 | // PathTracing Method (minimum settings(only direct light)) 147 | // - sampels: samples per lumel 148 | // - pathTracingRecLevel: max recursion depth 149 | "samples": 1, 150 | "pathTracingRecLevel": 0, 151 | 152 | // Ray direction 153 | // how to integrate over the hemisphere 154 | // direction for the rays [0-1], 155 | // 0: only in normal direction 156 | // 1: 180� direction(ideal diffuse) 157 | "importanceValue":1, 158 | 159 | // specificMeshBaking 160 | // Enable/disable specific baking 161 | // - ENABLED = default(bake all) 162 | // - DISABLED = bake all which have userDate.baking.bakeMe === true(bake only these) 163 | // - INVERTED = bakeMe===True ignores these to bake) 164 | "specificMeshBaking": THREE.LightBaking.SpecificMeshBakingEnum.DISABLED, 165 | 166 | // specificRayCasting 167 | //optional used for enable/disable ignoring objects, 168 | // - ENABLED = default(raycast all) 169 | // - DISABLED = bake all which have userDate.baking.intersectMe === true(use only these fot intersection tests) 170 | // - INVERTED = intersectMe===True ignores these to intersect) 171 | "specificRayCasting": THREE.LightBaking.SpecificRayCastingEnum.DISABLED, 172 | 173 | // Raycasting 174 | // - raycasterImplementation: choose between threejs raycaster implementation and octree(threejs preferred atm!) 175 | // - raycasterPrecision: set the raycaster precision. the lower the more precise 176 | "raycasterImplementation": THREE.LightBaking.RayCasterEnum.THREEJS, 177 | "raycasterPrecision": 0.0001, 178 | 179 | // softshadows 180 | // - softShadows: enable/disable soft shadows 181 | // - softShadowSamples: number of shadow samples fot the TWOPASS method. 182 | // - softShadowIntensity: used in direct light calculation, higher intensity results in brighter values 183 | "softShadows": true, 184 | "softShadowSamples": 1, 185 | "softShadowIntensity": 1, 186 | 187 | // giIntensity 188 | // increase it to boost the brightness of the indirect rays 189 | "giIntensity": 2, 190 | 191 | // lightAttenuation 192 | // - turn the light Attenuation for point lights on/off. Attenuation is derives from the standard point light attributes 193 | "lightAttenuation": false, 194 | 195 | // Lightmaps post processing: 196 | // applies an image processing filter onto the lightmap 197 | // postProcessingFilter: NONE/BOX/GAUSS, used to soften the lightmaps 198 | "postProcessingFilter": THREE.LightBaking.FilterEnum.NONE, 199 | 200 | } ); 201 | ``` 202 | 203 | #### Most common parameters: 204 | * to get a smooth/flat shading use: shading & ShadingEnum.Flat or ShadingEnum.PHONG 205 | * to get rid of seams use: packingOffset and/or uvSmoothing and set a higher texture width/height 206 | * to get indirect lighting use: samples > 0 rec level > 1 207 | * to get softshadows use: softshadows: true 208 | * to achieve a brighter lightmap: set giIntensity >= 2 209 | * to improve the pathtracing quality: the more samples the better the quality 210 | 211 | #### Import Scene 212 | ```html 213 | var lightBaking = THREE.LightBaking( { scene: scene } ); 214 | lightBaking.importLightMaps( "baked/Mailbox.zip" ); 215 | ``` 216 | #### Export Scene 217 | From developer Console: 218 | ```html 219 | lightBaking.exportLightMaps() 220 | ``` 221 | 222 | #### Editor 223 | To add our baking solution to the three.js editor you need to add the [Sidebar.LightBaking.js](https://github.com/manthrax/lightbaking/tree/master/js/Sidebar.LightBaking.js) into the editor/js folder. 224 | In addition, include the following files in the editors index.html: 225 | ```html 226 | 227 | 228 | ... 229 | 230 | ... 231 | ``` 232 | 233 | 234 | --- 235 | 236 | *Copyright (C) 2015 [Dominik Link](https://github.com/paradoxxl/), [Jan Pascal Tschudy](https://github.com/mem1b), [FHNW](http://www.fhnw.ch/)* 237 | *For full license and information, see [LICENSE](https://manthrax.github.com/lightbaking/LICENSE).* -------------------------------------------------------------------------------- /examples/ColoredLights.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Baked Colored Lights 5 | 6 | 7 | 8 | 9 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /examples/CornellBox.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Baked Cornell Box 5 | 6 | 7 | 8 | 9 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /examples/CornellBox_Textured.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Baked Cornell Box Textured 5 | 6 | 7 | 8 | 9 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 247 | 248 | 249 | 250 | -------------------------------------------------------------------------------- /examples/Mailbox.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Baked Mailbox 5 | 6 | 7 | 8 | 9 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /examples/Sponza.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Baked Sponza 5 | 6 | 7 | 8 | 9 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /examples/img/crate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/examples/img/crate.jpg -------------------------------------------------------------------------------- /examples/img/multicol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/examples/img/multicol.jpg -------------------------------------------------------------------------------- /examples/img/red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/examples/img/red.jpg -------------------------------------------------------------------------------- /js/DDSLoader.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | THREE.DDSLoader = function () { 6 | this._parser = THREE.DDSLoader.parse; 7 | }; 8 | 9 | THREE.DDSLoader.prototype = Object.create( THREE.CompressedTextureLoader.prototype ); 10 | THREE.DDSLoader.prototype.constructor = THREE.DDSLoader; 11 | 12 | THREE.DDSLoader.parse = function ( buffer, loadMipmaps ) { 13 | 14 | var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 }; 15 | 16 | // Adapted from @toji's DDS utils 17 | // https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js 18 | 19 | // All values and structures referenced from: 20 | // http://msdn.microsoft.com/en-us/library/bb943991.aspx/ 21 | 22 | var DDS_MAGIC = 0x20534444; 23 | 24 | var DDSD_CAPS = 0x1, 25 | DDSD_HEIGHT = 0x2, 26 | DDSD_WIDTH = 0x4, 27 | DDSD_PITCH = 0x8, 28 | DDSD_PIXELFORMAT = 0x1000, 29 | DDSD_MIPMAPCOUNT = 0x20000, 30 | DDSD_LINEARSIZE = 0x80000, 31 | DDSD_DEPTH = 0x800000; 32 | 33 | var DDSCAPS_COMPLEX = 0x8, 34 | DDSCAPS_MIPMAP = 0x400000, 35 | DDSCAPS_TEXTURE = 0x1000; 36 | 37 | var DDSCAPS2_CUBEMAP = 0x200, 38 | DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, 39 | DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, 40 | DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, 41 | DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, 42 | DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, 43 | DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, 44 | DDSCAPS2_VOLUME = 0x200000; 45 | 46 | var DDPF_ALPHAPIXELS = 0x1, 47 | DDPF_ALPHA = 0x2, 48 | DDPF_FOURCC = 0x4, 49 | DDPF_RGB = 0x40, 50 | DDPF_YUV = 0x200, 51 | DDPF_LUMINANCE = 0x20000; 52 | 53 | function fourCCToInt32( value ) { 54 | 55 | return value.charCodeAt(0) + 56 | (value.charCodeAt(1) << 8) + 57 | (value.charCodeAt(2) << 16) + 58 | (value.charCodeAt(3) << 24); 59 | 60 | } 61 | 62 | function int32ToFourCC( value ) { 63 | 64 | return String.fromCharCode( 65 | value & 0xff, 66 | (value >> 8) & 0xff, 67 | (value >> 16) & 0xff, 68 | (value >> 24) & 0xff 69 | ); 70 | } 71 | 72 | function loadARGBMip( buffer, dataOffset, width, height ) { 73 | var dataLength = width * height * 4; 74 | var srcBuffer = new Uint8Array( buffer, dataOffset, dataLength ); 75 | var byteArray = new Uint8Array( dataLength ); 76 | var dst = 0; 77 | var src = 0; 78 | for ( var y = 0; y < height; y ++ ) { 79 | for ( var x = 0; x < width; x ++ ) { 80 | var b = srcBuffer[src]; src ++; 81 | var g = srcBuffer[src]; src ++; 82 | var r = srcBuffer[src]; src ++; 83 | var a = srcBuffer[src]; src ++; 84 | byteArray[dst] = r; dst ++; //r 85 | byteArray[dst] = g; dst ++; //g 86 | byteArray[dst] = b; dst ++; //b 87 | byteArray[dst] = a; dst ++; //a 88 | } 89 | } 90 | return byteArray; 91 | } 92 | 93 | var FOURCC_DXT1 = fourCCToInt32("DXT1"); 94 | var FOURCC_DXT3 = fourCCToInt32("DXT3"); 95 | var FOURCC_DXT5 = fourCCToInt32("DXT5"); 96 | 97 | var headerLengthInt = 31; // The header length in 32 bit ints 98 | 99 | // Offsets into the header array 100 | 101 | var off_magic = 0; 102 | 103 | var off_size = 1; 104 | var off_flags = 2; 105 | var off_height = 3; 106 | var off_width = 4; 107 | 108 | var off_mipmapCount = 7; 109 | 110 | var off_pfFlags = 20; 111 | var off_pfFourCC = 21; 112 | var off_RGBBitCount = 22; 113 | var off_RBitMask = 23; 114 | var off_GBitMask = 24; 115 | var off_BBitMask = 25; 116 | var off_ABitMask = 26; 117 | 118 | var off_caps = 27; 119 | var off_caps2 = 28; 120 | var off_caps3 = 29; 121 | var off_caps4 = 30; 122 | 123 | // Parse header 124 | 125 | var header = new Int32Array( buffer, 0, headerLengthInt ); 126 | 127 | if ( header[ off_magic ] !== DDS_MAGIC ) { 128 | 129 | console.error( 'THREE.DDSLoader.parse: Invalid magic number in DDS header.' ); 130 | return dds; 131 | 132 | } 133 | 134 | if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) { 135 | 136 | console.error( 'THREE.DDSLoader.parse: Unsupported format, must contain a FourCC code.' ); 137 | return dds; 138 | 139 | } 140 | 141 | var blockBytes; 142 | 143 | var fourCC = header[ off_pfFourCC ]; 144 | 145 | var isRGBAUncompressed = false; 146 | 147 | switch ( fourCC ) { 148 | 149 | case FOURCC_DXT1: 150 | 151 | blockBytes = 8; 152 | dds.format = THREE.RGB_S3TC_DXT1_Format; 153 | break; 154 | 155 | case FOURCC_DXT3: 156 | 157 | blockBytes = 16; 158 | dds.format = THREE.RGBA_S3TC_DXT3_Format; 159 | break; 160 | 161 | case FOURCC_DXT5: 162 | 163 | blockBytes = 16; 164 | dds.format = THREE.RGBA_S3TC_DXT5_Format; 165 | break; 166 | 167 | default: 168 | 169 | if ( header[off_RGBBitCount] == 32 170 | && header[off_RBitMask]&0xff0000 171 | && header[off_GBitMask]&0xff00 172 | && header[off_BBitMask]&0xff 173 | && header[off_ABitMask]&0xff000000 ) { 174 | isRGBAUncompressed = true; 175 | blockBytes = 64; 176 | dds.format = THREE.RGBAFormat; 177 | } else { 178 | console.error( 'THREE.DDSLoader.parse: Unsupported FourCC code ', int32ToFourCC( fourCC ) ); 179 | return dds; 180 | } 181 | } 182 | 183 | dds.mipmapCount = 1; 184 | 185 | if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) { 186 | 187 | dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] ); 188 | 189 | } 190 | 191 | //TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc. 192 | 193 | dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false; 194 | 195 | dds.width = header[ off_width ]; 196 | dds.height = header[ off_height ]; 197 | 198 | var dataOffset = header[ off_size ] + 4; 199 | 200 | // Extract mipmaps buffers 201 | 202 | var width = dds.width; 203 | var height = dds.height; 204 | 205 | var faces = dds.isCubemap ? 6 : 1; 206 | 207 | for ( var face = 0; face < faces; face ++ ) { 208 | 209 | for ( var i = 0; i < dds.mipmapCount; i ++ ) { 210 | 211 | if ( isRGBAUncompressed ) { 212 | var byteArray = loadARGBMip( buffer, dataOffset, width, height ); 213 | var dataLength = byteArray.length; 214 | } else { 215 | var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes; 216 | var byteArray = new Uint8Array( buffer, dataOffset, dataLength ); 217 | } 218 | 219 | var mipmap = { "data": byteArray, "width": width, "height": height }; 220 | dds.mipmaps.push( mipmap ); 221 | 222 | dataOffset += dataLength; 223 | 224 | width = Math.max( width * 0.5, 1 ); 225 | height = Math.max( height * 0.5, 1 ); 226 | 227 | } 228 | 229 | width = dds.width; 230 | height = dds.height; 231 | 232 | } 233 | 234 | return dds; 235 | 236 | }; 237 | 238 | -------------------------------------------------------------------------------- /js/LightBakingDemo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Jan Pascal Tschudy on 17.08.2015. 3 | */ 4 | 5 | var lightBakingDemo = function (plbparams) { 6 | var tracker; 7 | 8 | var startMsg = "Start baking!<\a>"; 9 | var importLMMsg = "" + 10 | "Select lightmap files"; 11 | var previewMsg = "Display Lightmaps<\a>"; 12 | var exportLMMsg = "Export Lightmaps<\a>"; 13 | var resetCamMsg = "Reset Camera<\a>"; 14 | 15 | // create datgui object and it's settings 16 | var datguiWrapper = (function (lbparams) { 17 | 18 | var lightBakingConfig; 19 | var lightBakingDatGui = new dat.GUI(); 20 | 21 | function getDatGui() { 22 | 23 | return lightBakingDatGui; 24 | 25 | } 26 | 27 | function getLightBakingConfig() { 28 | 29 | return lightBakingConfig.runParams; 30 | 31 | } 32 | 33 | // function descriptor? 34 | var lightbakingDatguiConfig = function (defParams, scene) { 35 | 36 | this.runParams = JSON.parse(JSON.stringify(defParams)); 37 | this.runParams.scene = scene; 38 | 39 | this.appMode = defParams.appMode; 40 | this.workerLimit = defParams.workerLimit; 41 | this.debugText = defParams.debugText; 42 | this.textureSize = defParams.textureHeight; 43 | this.shading = defParams.shading; 44 | 45 | this.giIntensity = defParams.giIntensity; 46 | this.lightAttenuation = defParams.lightAttenuation; 47 | 48 | this.postProcessingFilter = defParams.postProcessingFilter; 49 | 50 | this.uvMethod = defParams.uvMethod; 51 | this.packingOffset = defParams.packingOffset; 52 | this.uvSmoothing = defParams.uvSmoothing; 53 | 54 | this.samples = defParams.samples; 55 | this.pathTracingRecLevel = defParams.pathTracingRecLevel; 56 | 57 | this.softShadows = defParams.softShadows; 58 | this.softShadowSamples = defParams.softShadowSamples; 59 | this.softShadowIntensity = defParams.softShadowIntensity; 60 | 61 | }; 62 | 63 | function setNewLightBakingConfig(defParams, scene) { 64 | 65 | if (lightBakingConfig === undefined) { 66 | 67 | lightBakingConfig = new lightbakingDatguiConfig(defParams, scene); 68 | 69 | } else { 70 | 71 | lightBakingConfig.runParams = JSON.parse(JSON.stringify(defParams)); 72 | lightBakingConfig.runParams.scene = scene; 73 | 74 | lightBakingConfig.appMode = defParams.appMode; 75 | lightBakingConfig.workerLimit = defParams.workerLimit; 76 | lightBakingConfig.debugText = defParams.debugText; 77 | lightBakingConfig.textureSize = defParams.textureHeight; 78 | lightBakingConfig.shading = defParams.shading; 79 | 80 | lightBakingConfig.giIntensity = defParams.giIntensity; 81 | lightBakingConfig.lightAttenuation = defParams.lightAttenuation; 82 | 83 | lightBakingConfig.postProcessingFilter = defParams.postProcessingFilter; 84 | 85 | lightBakingConfig.uvMethod = defParams.uvMethod; 86 | lightBakingConfig.packingOffset = defParams.packingOffset; 87 | lightBakingConfig.uvSmoothing = defParams.uvSmoothing; 88 | 89 | lightBakingConfig.samples = defParams.samples; 90 | lightBakingConfig.pathTracingRecLevel = defParams.pathTracingRecLevel; 91 | 92 | lightBakingConfig.softShadows = defParams.softShadows; 93 | lightBakingConfig.softShadowSamples = defParams.softShadowSamples; 94 | lightBakingConfig.softShadowIntensity = defParams.softShadowIntensity; 95 | 96 | } 97 | 98 | } 99 | 100 | setNewLightBakingConfig(THREE.LightBaking.parse(lbparams, THREE.LightBaking.getDefaultConfig()), lbparams.scene); 101 | 102 | // Lightbaking Options 103 | (function () { 104 | 105 | var lightBakingFolder = lightBakingDatGui.addFolder('Lightbaking options'); 106 | lightBakingFolder.open(); 107 | 108 | // Main FOLDER 109 | lightBakingFolder.add(lightBakingConfig, 'appMode', THREE.LightBaking.ApplicationExecutionEnum).name("Execution Model").onChange(function () { 110 | lightBakingConfig.runParams.appMode = parseInt(lightBakingConfig.appMode, 10); 111 | }); 112 | lightBakingFolder.add(lightBakingConfig, 'workerLimit').name("Worker limit").onChange(function () { 113 | lightBakingConfig.runParams.workerLimit = parseInt(lightBakingConfig.workerLimit, 10); 114 | }).min(1).step(1); 115 | 116 | lightBakingFolder.add(lightBakingConfig, 'debugText').name("Debug Text").onChange(function () { 117 | lightBakingConfig.runParams.debugText = lightBakingConfig.debugText; 118 | }); 119 | lightBakingFolder.add(lightBakingConfig, 'textureSize').name("Lightmap size").onChange(function () { 120 | lightBakingConfig.runParams.textureWidth = parseInt(lightBakingConfig.textureSize, 10); 121 | lightBakingConfig.runParams.textureHeight = parseInt(lightBakingConfig.textureSize, 10); 122 | }).min(2).step(1); // TODO STEP 123 | 124 | lightBakingFolder.add(lightBakingConfig, 'shading', THREE.LightBaking.ShadingEnum).name("Shading").onChange(function () { 125 | lightBakingConfig.runParams.shading = parseInt(lightBakingConfig.shading, 10); 126 | }); 127 | 128 | lightBakingFolder.add(lightBakingConfig, 'giIntensity').name("Intensity").onChange(function () { 129 | lightBakingConfig.runParams.giIntensity = parseFloat(lightBakingConfig.giIntensity); 130 | }).min(0); 131 | 132 | lightBakingFolder.add(lightBakingConfig, 'lightAttenuation').name("Light Attenuation").onChange(function () { 133 | lightBakingConfig.runParams.lightAttenuation = lightBakingConfig.lightAttenuation; 134 | }); 135 | 136 | lightBakingFolder.add(lightBakingConfig, 'postProcessingFilter', THREE.LightBaking.FilterEnum).name("ImageProcessing").onChange(function () { 137 | lightBakingConfig.runParams.postProcessingFilter = lightBakingConfig.postProcessingFilter; 138 | }); 139 | 140 | // Path Tracing FOLDER 141 | var ptFolder = lightBakingFolder.addFolder('Path Tracing'); 142 | ptFolder.open(); 143 | 144 | ptFolder.add(lightBakingConfig, 'samples').name("Samples").onChange(function () { 145 | lightBakingConfig.runParams.samples = parseInt(lightBakingConfig.samples, 10); 146 | }).min(0).step(1); 147 | 148 | ptFolder.add(lightBakingConfig, 'pathTracingRecLevel').name("Recursion depth").onChange(function () { 149 | lightBakingConfig.runParams.pathTracingRecLevel = parseInt(lightBakingConfig.pathTracingRecLevel, 10); 150 | }).min(0).step(1); 151 | 152 | // SoftShadows 153 | var ssFolder = lightBakingFolder.addFolder('Soft shadows'); 154 | ssFolder.close(); 155 | 156 | ssFolder.add(lightBakingConfig, 'softShadows').name("Enabled").onChange(function () { 157 | lightBakingConfig.runParams.softShadows = lightBakingConfig.softShadows; 158 | }); 159 | 160 | ssFolder.add(lightBakingConfig, 'softShadowSamples').name("Samples").onChange(function () { 161 | lightBakingConfig.runParams.softShadowSamples = parseInt(lightBakingConfig.softShadowSamples, 10); 162 | }).min(0).step(1); 163 | 164 | ssFolder.add(lightBakingConfig, 'softShadowIntensity').name("Intensity Factor").onChange(function () { 165 | lightBakingConfig.runParams.softShadowIntensity = parseFloat(lightBakingConfig.softShadowIntensity); 166 | }).min(0).step(1); 167 | 168 | // UV FOLDER 169 | var uvFolder = lightBakingFolder.addFolder('UV related'); 170 | uvFolder.close(); 171 | 172 | uvFolder.add(lightBakingConfig, 'uvMethod', THREE.LightBaking.UVMethodEnum).name("UV-Method").onChange(function () { 173 | lightBakingConfig.runParams.uvMethod = parseInt(lightBakingConfig.uvMethod, 10); 174 | }); 175 | 176 | uvFolder.add(lightBakingConfig, 'packingOffset').name("Packing-Offset").onChange(function () { 177 | lightBakingConfig.runParams.packingOffset = parseFloat(lightBakingConfig.packingOffset); 178 | }).min(0).step(1); 179 | 180 | uvFolder.add(lightBakingConfig, 'uvSmoothing').name("Smoothing").onChange(function () { 181 | lightBakingConfig.runParams.uvSmoothing = parseFloat(lightBakingConfig.uvSmoothing); 182 | }).step(0.01); 183 | 184 | })(); 185 | 186 | return { 187 | getLightBakingConfig: getLightBakingConfig, 188 | setNewLightBakingConfig: setNewLightBakingConfig, 189 | getDatGui: getDatGui 190 | }; 191 | 192 | })(plbparams); 193 | 194 | // --- Tracker 195 | // bottom container 196 | var container = document.createElement('div'); 197 | container.style.position = 'absolute'; 198 | container.style.bottom = '0'; 199 | container.style.width = '100%'; 200 | container.style.textAlign = 'center'; 201 | document.body.appendChild(container); 202 | 203 | // tracker 204 | tracker = document.createElement('div'); 205 | tracker.style.width = '100%'; 206 | tracker.style.padding = '10px'; 207 | tracker.style.background = '#d3d3d3'; 208 | container.appendChild(tracker); 209 | 210 | function handleFiles(evt) { 211 | var objectURL = window.URL.createObjectURL(evt[0]); 212 | importScene(objectURL); 213 | } 214 | 215 | tracker.innerHTML = (function () { 216 | return startMsg + " - " + importLMMsg + " - " + resetCamMsg; 217 | })(); 218 | 219 | (function () { 220 | 221 | var fileSelect = document.getElementById("fileSelect"), 222 | fileElem = document.getElementById("fileElem"); 223 | 224 | fileSelect.addEventListener("click", function (e) { 225 | if (fileElem) { 226 | fileElem.click(); 227 | } 228 | e.preventDefault(); // prevent navigation to "#" 229 | }, false); 230 | 231 | })(); 232 | 233 | // --- Import a scene 234 | function importScene(url) { 235 | 236 | var lightBaking = THREE.LightBaking({scene: scene}); 237 | lightBaking.importLightMaps(url, function (config) { 238 | 239 | var gui = datguiWrapper.getDatGui(); 240 | 241 | datguiWrapper.setNewLightBakingConfig(THREE.LightBaking.parse(config, THREE.LightBaking.getDefaultConfig()), scene); 242 | 243 | var iterate = function (folders) { 244 | 245 | Object.keys(folders).forEach(function (key) { 246 | var folder = folders[key]; 247 | var newFolders = Object.keys(folder.__folders); 248 | 249 | if (folder.__controllers !== undefined && folder.__controllers.length !== 0) { 250 | folder.__controllers.forEach(function (c) { 251 | c.updateDisplay(); 252 | }) 253 | } 254 | 255 | if (newFolders.length > 0) { 256 | newFolders.forEach(function (f) { 257 | iterate(folder.__folders); 258 | }); 259 | } 260 | }); 261 | 262 | }; 263 | 264 | iterate(gui.__folders); 265 | 266 | render(); 267 | render(); 268 | }); 269 | } 270 | 271 | // --- Lightbaking 272 | function lightBakingRun() { 273 | 274 | var baked = 0; 275 | var toBake = lightBaking.getMeshesToBakeCount(); 276 | var tt0 = Date.now(); 277 | 278 | tracker.innerHTML = "Started baking for " + toBake + " Meshes."; 279 | 280 | function getMsg() { 281 | 282 | return (baked === toBake ? baked : ++baked) + "/" + toBake + " Meshes baked"; 283 | 284 | } 285 | 286 | lightBaking.setOnMeshBaked(function () { 287 | 288 | tracker.innerHTML = getMsg(); 289 | 290 | lightBaking.log("setOnMeshBaked() called - & calling render()"); 291 | render(); 292 | render(); 293 | 294 | }); 295 | 296 | lightBaking.setAfterExecuted(function () { 297 | 298 | var timeMsg = " - " + ((Date.now() - tt0) / 1000) + "s"; 299 | var msg = startMsg + " - " + getMsg() + timeMsg + " - " + previewMsg + " - " + exportLMMsg + " - " + importLMMsg + " - " + resetCamMsg; 300 | tracker.innerHTML = msg; 301 | 302 | }); 303 | 304 | } 305 | 306 | // --- What to expose 307 | return { 308 | lightBakingRun: lightBakingRun, 309 | handleFiles: handleFiles, 310 | getLightBakingConfig: datguiWrapper.getLightBakingConfig 311 | }; 312 | 313 | }; 314 | -------------------------------------------------------------------------------- /js/LightBakingWorker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Jan Pascal Tschudy on 20.06.2015. 3 | * 4 | * Setup has to be the first Method call(before meshTask or faceTask). It initializes the lightBaking Attribute. 5 | * 6 | * Future improvements: 7 | * - Use structured cloning instead of transferring a json object. 8 | * 9 | */ 10 | 11 | "use strict"; 12 | 13 | importScripts("three.js"); 14 | importScripts("LightBaking.js"); 15 | 16 | var workerCtx = (function () { 17 | 18 | var lightBaking; 19 | var sceneRef; 20 | var intent; 21 | var workerId; 22 | 23 | function onMessage(e) { 24 | 25 | intent = e.data.task.intent; 26 | workerId = e.data.workerId; 27 | 28 | switch (e.data.task.intent) { 29 | 30 | case "Setup": 31 | 32 | sceneSetup(e); 33 | lightBaking.log(intent); 34 | 35 | break; 36 | 37 | case THREE.LightBaking.WorkerTaskEnum.MESH: 38 | 39 | lightBaking.setWorkerId(workerId); 40 | lightBaking.incWorkerTaskId(); 41 | lightBaking.log(intent); 42 | meshTask(e); 43 | 44 | break; 45 | 46 | case THREE.LightBaking.WorkerTaskEnum.FACE: 47 | 48 | lightBaking.setWorkerId(workerId); 49 | lightBaking.incWorkerTaskId(); 50 | lightBaking.log(intent); 51 | faceTask(e); 52 | 53 | break; 54 | 55 | default : 56 | 57 | self.console.log(intent + " not yet implemented."); 58 | break; 59 | 60 | } 61 | 62 | } 63 | 64 | function faceTask(e) { 65 | 66 | } 67 | 68 | function meshTask(e) { 69 | 70 | // only bake specific Mesh 71 | sceneRef.traverse(function (mesh) { 72 | 73 | if (mesh instanceof THREE.Mesh) { 74 | 75 | mesh.userData.baking.bakeMe = ( mesh.uuid === e.data.task.uuid ); 76 | 77 | } 78 | 79 | }); 80 | 81 | lightBaking.run(function () { 82 | setListener(JSON.parse(lightBaking.toJSON())); 83 | }); 84 | } 85 | 86 | function sceneSetup(evt) { 87 | 88 | var scene; 89 | var config = JSON.parse(evt.data.bakingConfigJSON); 90 | 91 | // must be defined before importScene(), otherwise Octree would be unknown 92 | if (config.raycasterImplementation === THREE.LightBaking.RayCasterEnum.OCTREE) { 93 | 94 | importScripts("Octree.js"); 95 | 96 | } 97 | 98 | // reconstruct scene in worker 99 | scene = importScene(evt); 100 | sceneRef = scene; 101 | 102 | // adjust some attributes to work properly in worker 103 | config.appMode = THREE.LightBaking.ApplicationExecutionEnum.SINGLETHREADED; 104 | config.specificMeshBaking = THREE.LightBaking.SpecificMeshBakingEnum.ENABLED; 105 | config.workerId = evt.data.workerId; 106 | config.scene = scene; 107 | 108 | if (config.uvMethod === THREE.LightBaking.UVMethodEnum.PACKED) { 109 | 110 | importScripts("packer.growing.js"); 111 | 112 | } 113 | 114 | lightBaking = new THREE.LightBaking(config); 115 | 116 | } 117 | 118 | function setListener(config) { 119 | 120 | lightBaking.setAfterExecuted(function () { 121 | 122 | lightBaking.log("afterExecuted() - send Finished to main thread."); 123 | 124 | self.postMessage({ 125 | 126 | workerId: workerId, 127 | intent: THREE.LightBaking.WorkerTaskEnum.FINISHED 128 | 129 | }); 130 | 131 | }); 132 | 133 | if (config.workerTaskMode === THREE.LightBaking.WorkerTaskEnum.MESH) { 134 | 135 | lightBaking.setOnMeshBaked(ownPostMessage); 136 | 137 | } 138 | 139 | if (config.postProcessingFilter !== THREE.LightBaking.FilterEnum.NONE) { 140 | 141 | lightBaking.setOnFilterOnTextureApplied(ownPostMessage); 142 | 143 | } 144 | 145 | } 146 | 147 | function ownPostMessage(mesh) { 148 | 149 | lightBaking.log("setOnMeshBaked() - postMessage, intent:" + intent); 150 | 151 | self.postMessage({ 152 | 153 | texBuf: mesh.material.lightMap.image.data, 154 | uvLightmap: mesh.geometry.faceVertexUvs[1], 155 | uvInfo: mesh.userData.baking.uvInfo, 156 | workerId: workerId, 157 | meshUUID: mesh.uuid, 158 | intent: intent 159 | 160 | }); 161 | 162 | } 163 | 164 | function importScene(evt) { 165 | 166 | var scene; 167 | // JSONLoader? 168 | // OBJ Loader? 169 | // Three.ObjectLoader! 170 | // quote: Unlike the JSONLoader, this one make use of the .type attributes of objects to map them to their original classes. 171 | 172 | // ObjectLoader does not handle AreaLights atm. 173 | var loader = new THREE.ObjectLoader(); 174 | loader.parse(evt.data.sceneJSON, function (obj) { 175 | 176 | var matrix = new THREE.Matrix4(); 177 | var object; 178 | 179 | // ADD AREALIGHT! 180 | evt.data.sceneJSON.object.children.forEach(function (data) { 181 | 182 | if (data.type === (THREE.RectAreaLight?"RectAreaLight":"AreaLight")) { 183 | 184 | object = new (THREE.RectAreaLight?THREE.RectAreaLight:THREE.AreaLight)(data.color, data.intensity,data.width,data.height); 185 | 186 | object.width = data.width; 187 | object.height = data.height; 188 | 189 | object.constantAttenuation = data.constantAttenuation; 190 | object.linearAttenuation = data.linearAttenuation; 191 | object.quadraticAttenuation = data.quadraticAttenuation; 192 | 193 | object.uuid = data.uuid; 194 | 195 | if (data.name !== undefined) { 196 | 197 | object.name = data.name; 198 | 199 | } 200 | 201 | if (data.matrix !== undefined) { 202 | 203 | matrix.fromArray(data.matrix); 204 | matrix.decompose(object.position, object.quaternion, object.scale); 205 | 206 | } else { 207 | 208 | if (data.position !== undefined) { 209 | 210 | object.position.fromArray(data.position); 211 | 212 | } 213 | 214 | if (data.rotation !== undefined) { 215 | 216 | object.rotation.fromArray(data.rotation); 217 | 218 | } 219 | 220 | if (data.scale !== undefined) { 221 | 222 | object.scale.fromArray(data.scale); 223 | 224 | } 225 | 226 | } 227 | 228 | if (data.visible !== undefined) { 229 | object.visible = data.visible; 230 | } 231 | if (data.userData !== undefined) { 232 | object.userData = data.userData; 233 | } 234 | 235 | obj.add(object); 236 | 237 | } 238 | 239 | }); 240 | 241 | evt.data.sceneJSON.materials.forEach(function (data) { 242 | 243 | if ((data.type === "MeshBasicMaterial" || data.type === "MeshLambertMaterial" || data.type === "MeshPhongmaterial" ) && data.map !== undefined) { 244 | 245 | obj.traverse( 246 | function (mesh) { 247 | 248 | if (mesh.material !== undefined && mesh.material.uuid === data.uuid) { 249 | mesh.material.map = data.map; 250 | } 251 | 252 | } 253 | ); 254 | } 255 | 256 | }); 257 | 258 | 259 | scene = obj; 260 | 261 | }); 262 | 263 | return scene; 264 | 265 | } 266 | 267 | return { 268 | onMessage: onMessage 269 | }; 270 | 271 | })(); 272 | 273 | self.onmessage = function (e) { 274 | 275 | workerCtx.onMessage(e); 276 | 277 | }; 278 | 279 | 280 | 281 | 282 | -------------------------------------------------------------------------------- /js/MTLLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Loads a Wavefront .mtl file specifying materials 3 | * 4 | * @author angelxuanchang 5 | */ 6 | 7 | THREE.MTLLoader = function( baseUrl, options, crossOrigin ) { 8 | 9 | this.baseUrl = baseUrl; 10 | this.options = options; 11 | this.crossOrigin = crossOrigin; 12 | 13 | }; 14 | 15 | THREE.MTLLoader.prototype = { 16 | 17 | constructor: THREE.MTLLoader, 18 | 19 | load: function ( url, onLoad, onProgress, onError ) { 20 | 21 | var scope = this; 22 | 23 | var loader = new THREE.XHRLoader(); 24 | loader.setCrossOrigin( this.crossOrigin ); 25 | loader.load( url, function ( text ) { 26 | 27 | onLoad( scope.parse( text ) ); 28 | 29 | }, onProgress, onError ); 30 | 31 | }, 32 | 33 | /** 34 | * Parses loaded MTL file 35 | * @param text - Content of MTL file 36 | * @return {THREE.MTLLoader.MaterialCreator} 37 | */ 38 | parse: function ( text ) { 39 | 40 | var lines = text.split( "\n" ); 41 | var info = {}; 42 | var delimiter_pattern = /\s+/; 43 | var materialsInfo = {}; 44 | 45 | for ( var i = 0; i < lines.length; i ++ ) { 46 | 47 | var line = lines[ i ]; 48 | line = line.trim(); 49 | 50 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) { 51 | 52 | // Blank line or comment ignore 53 | continue; 54 | 55 | } 56 | 57 | var pos = line.indexOf( ' ' ); 58 | 59 | var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line; 60 | key = key.toLowerCase(); 61 | 62 | var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : ""; 63 | value = value.trim(); 64 | 65 | if ( key === "newmtl" ) { 66 | 67 | // New material 68 | 69 | info = { name: value }; 70 | materialsInfo[ value ] = info; 71 | 72 | } else if ( info ) { 73 | 74 | if ( key === "ka" || key === "kd" || key === "ks" ) { 75 | 76 | var ss = value.split( delimiter_pattern, 3 ); 77 | info[ key ] = [ parseFloat( ss[0] ), parseFloat( ss[1] ), parseFloat( ss[2] ) ]; 78 | 79 | } else { 80 | 81 | info[ key ] = value; 82 | 83 | } 84 | 85 | } 86 | 87 | } 88 | 89 | var materialCreator = new THREE.MTLLoader.MaterialCreator( this.baseUrl, this.options ); 90 | materialCreator.crossOrigin = this.crossOrigin 91 | materialCreator.setMaterials( materialsInfo ); 92 | return materialCreator; 93 | 94 | } 95 | 96 | }; 97 | 98 | /** 99 | * Create a new THREE-MTLLoader.MaterialCreator 100 | * @param baseUrl - Url relative to which textures are loaded 101 | * @param options - Set of options on how to construct the materials 102 | * side: Which side to apply the material 103 | * THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide 104 | * wrap: What type of wrapping to apply for textures 105 | * THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping 106 | * normalizeRGB: RGBs need to be normalized to 0-1 from 0-255 107 | * Default: false, assumed to be already normalized 108 | * ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's 109 | * Default: false 110 | * invertTransparency: If transparency need to be inverted (inversion is needed if d = 0 is fully opaque) 111 | * Default: false (d = 1 is fully opaque) 112 | * @constructor 113 | */ 114 | 115 | THREE.MTLLoader.MaterialCreator = function( baseUrl, options ) { 116 | 117 | this.baseUrl = baseUrl; 118 | this.options = options; 119 | this.materialsInfo = {}; 120 | this.materials = {}; 121 | this.materialsArray = []; 122 | this.nameLookup = {}; 123 | 124 | this.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide; 125 | this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping; 126 | 127 | }; 128 | 129 | THREE.MTLLoader.MaterialCreator.prototype = { 130 | 131 | constructor: THREE.MTLLoader.MaterialCreator, 132 | 133 | setMaterials: function( materialsInfo ) { 134 | 135 | this.materialsInfo = this.convert( materialsInfo ); 136 | this.materials = {}; 137 | this.materialsArray = []; 138 | this.nameLookup = {}; 139 | 140 | }, 141 | 142 | convert: function( materialsInfo ) { 143 | 144 | if ( !this.options ) return materialsInfo; 145 | 146 | var converted = {}; 147 | 148 | for ( var mn in materialsInfo ) { 149 | 150 | // Convert materials info into normalized form based on options 151 | 152 | var mat = materialsInfo[ mn ]; 153 | 154 | var covmat = {}; 155 | 156 | converted[ mn ] = covmat; 157 | 158 | for ( var prop in mat ) { 159 | 160 | var save = true; 161 | var value = mat[ prop ]; 162 | var lprop = prop.toLowerCase(); 163 | 164 | switch ( lprop ) { 165 | 166 | case 'kd': 167 | case 'ka': 168 | case 'ks': 169 | 170 | // Diffuse color (color under white light) using RGB values 171 | 172 | if ( this.options && this.options.normalizeRGB ) { 173 | 174 | value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ]; 175 | 176 | } 177 | 178 | if ( this.options && this.options.ignoreZeroRGBs ) { 179 | 180 | if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 1 ] === 0 ) { 181 | 182 | // ignore 183 | 184 | save = false; 185 | 186 | } 187 | } 188 | 189 | break; 190 | 191 | case 'd': 192 | 193 | // According to MTL format (http://paulbourke.net/dataformats/mtl/): 194 | // d is dissolve for current material 195 | // factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent) 196 | 197 | if ( this.options && this.options.invertTransparency ) { 198 | 199 | value = 1 - value; 200 | 201 | } 202 | 203 | break; 204 | 205 | default: 206 | 207 | break; 208 | } 209 | 210 | if ( save ) { 211 | 212 | covmat[ lprop ] = value; 213 | 214 | } 215 | 216 | } 217 | 218 | } 219 | 220 | return converted; 221 | 222 | }, 223 | 224 | preload: function () { 225 | 226 | for ( var mn in this.materialsInfo ) { 227 | 228 | this.create( mn ); 229 | 230 | } 231 | 232 | }, 233 | 234 | getIndex: function( materialName ) { 235 | 236 | return this.nameLookup[ materialName ]; 237 | 238 | }, 239 | 240 | getAsArray: function() { 241 | 242 | var index = 0; 243 | 244 | for ( var mn in this.materialsInfo ) { 245 | 246 | this.materialsArray[ index ] = this.create( mn ); 247 | this.nameLookup[ mn ] = index; 248 | index ++; 249 | 250 | } 251 | 252 | return this.materialsArray; 253 | 254 | }, 255 | 256 | create: function ( materialName ) { 257 | 258 | if ( this.materials[ materialName ] === undefined ) { 259 | 260 | this.createMaterial_( materialName ); 261 | 262 | } 263 | 264 | return this.materials[ materialName ]; 265 | 266 | }, 267 | 268 | createMaterial_: function ( materialName ) { 269 | 270 | // Create material 271 | 272 | var mat = this.materialsInfo[ materialName ]; 273 | var params = { 274 | 275 | name: materialName, 276 | side: this.side 277 | 278 | }; 279 | 280 | for ( var prop in mat ) { 281 | 282 | var value = mat[ prop ]; 283 | 284 | switch ( prop.toLowerCase() ) { 285 | 286 | // Ns is material specular exponent 287 | 288 | case 'kd': 289 | 290 | // Diffuse color (color under white light) using RGB values 291 | 292 | params[ 'diffuse' ] = new THREE.Color().fromArray( value ); 293 | 294 | break; 295 | 296 | case 'ka': 297 | 298 | // Ambient color (color under shadow) using RGB values 299 | 300 | break; 301 | 302 | case 'ks': 303 | 304 | // Specular color (color when light is reflected from shiny surface) using RGB values 305 | params[ 'specular' ] = new THREE.Color().fromArray( value ); 306 | 307 | break; 308 | 309 | case 'map_kd': 310 | 311 | // Diffuse texture map 312 | 313 | params[ 'map' ] = this.loadTexture( this.baseUrl + value ); 314 | params[ 'map' ].wrapS = this.wrap; 315 | params[ 'map' ].wrapT = this.wrap; 316 | 317 | break; 318 | 319 | case 'ns': 320 | 321 | // The specular exponent (defines the focus of the specular highlight) 322 | // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000. 323 | 324 | params['shininess'] = value; 325 | 326 | break; 327 | 328 | case 'd': 329 | 330 | // According to MTL format (http://paulbourke.net/dataformats/mtl/): 331 | // d is dissolve for current material 332 | // factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent) 333 | 334 | if ( value < 1 ) { 335 | 336 | params['transparent'] = true; 337 | params['opacity'] = value; 338 | 339 | } 340 | 341 | break; 342 | 343 | case 'map_bump': 344 | case 'bump': 345 | 346 | // Bump texture map 347 | 348 | if ( params[ 'bumpMap' ] ) break; // Avoid loading twice. 349 | 350 | params[ 'bumpMap' ] = this.loadTexture( this.baseUrl + value ); 351 | params[ 'bumpMap' ].wrapS = this.wrap; 352 | params[ 'bumpMap' ].wrapT = this.wrap; 353 | 354 | break; 355 | 356 | default: 357 | break; 358 | 359 | } 360 | 361 | } 362 | 363 | if ( params[ 'diffuse' ] ) { 364 | 365 | params[ 'color' ] = params[ 'diffuse' ]; 366 | 367 | } 368 | 369 | this.materials[ materialName ] = new THREE.MeshPhongMaterial( params ); 370 | return this.materials[ materialName ]; 371 | 372 | }, 373 | 374 | 375 | loadTexture: function ( url, mapping, onLoad, onError ) { 376 | 377 | var texture; 378 | var loader = THREE.Loader.Handlers.get( url ); 379 | 380 | if ( loader !== null ) { 381 | 382 | texture = loader.load( url, onLoad ); 383 | 384 | } else { 385 | 386 | texture = new THREE.Texture(); 387 | 388 | loader = new THREE.ImageLoader(); 389 | loader.crossOrigin = this.crossOrigin; 390 | loader.load( url, function ( image ) { 391 | 392 | texture.image = THREE.MTLLoader.ensurePowerOfTwo_( image ); 393 | texture.needsUpdate = true; 394 | 395 | if ( onLoad ) onLoad( texture ); 396 | 397 | } ); 398 | 399 | } 400 | 401 | if ( mapping !== undefined ) texture.mapping = mapping; 402 | 403 | return texture; 404 | 405 | } 406 | 407 | }; 408 | 409 | THREE.MTLLoader.ensurePowerOfTwo_ = function ( image ) { 410 | 411 | if ( ! THREE.Math.isPowerOfTwo( image.width ) || ! THREE.Math.isPowerOfTwo( image.height ) ) { 412 | 413 | var canvas = document.createElement( "canvas" ); 414 | canvas.width = THREE.MTLLoader.nextHighestPowerOfTwo_( image.width ); 415 | canvas.height = THREE.MTLLoader.nextHighestPowerOfTwo_( image.height ); 416 | 417 | var ctx = canvas.getContext("2d"); 418 | ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); 419 | return canvas; 420 | 421 | } 422 | 423 | return image; 424 | 425 | }; 426 | 427 | THREE.MTLLoader.nextHighestPowerOfTwo_ = function( x ) { 428 | 429 | -- x; 430 | 431 | for ( var i = 1; i < 32; i <<= 1 ) { 432 | 433 | x = x | x >> i; 434 | 435 | } 436 | 437 | return x + 1; 438 | 439 | }; 440 | 441 | THREE.EventDispatcher.prototype.apply( THREE.MTLLoader.prototype ); 442 | -------------------------------------------------------------------------------- /js/OBJLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | THREE.OBJLoader = function ( manager ) { 6 | 7 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 8 | 9 | }; 10 | 11 | THREE.OBJLoader.prototype = { 12 | 13 | constructor: THREE.OBJLoader, 14 | 15 | load: function ( url, onLoad, onProgress, onError ) { 16 | 17 | var scope = this; 18 | 19 | var loader = new THREE.XHRLoader( scope.manager ); 20 | loader.setCrossOrigin( this.crossOrigin ); 21 | loader.load( url, function ( text ) { 22 | 23 | onLoad( scope.parse( text ) ); 24 | 25 | }, onProgress, onError ); 26 | 27 | }, 28 | 29 | parse: function ( text ) { 30 | 31 | console.time( 'OBJLoader' ); 32 | 33 | var object, objects = []; 34 | var geometry, material; 35 | 36 | function parseVertexIndex( value ) { 37 | 38 | var index = parseInt( value ); 39 | 40 | return ( index >= 0 ? index - 1 : index + vertices.length / 3 ) * 3; 41 | 42 | } 43 | 44 | function parseNormalIndex( value ) { 45 | 46 | var index = parseInt( value ); 47 | 48 | return ( index >= 0 ? index - 1 : index + normals.length / 3 ) * 3; 49 | 50 | } 51 | 52 | function parseUVIndex( value ) { 53 | 54 | var index = parseInt( value ); 55 | 56 | return ( index >= 0 ? index - 1 : index + uvs.length / 2 ) * 2; 57 | 58 | } 59 | 60 | function addVertex( a, b, c ) { 61 | 62 | geometry.vertices.push( 63 | vertices[ a ], vertices[ a + 1 ], vertices[ a + 2 ], 64 | vertices[ b ], vertices[ b + 1 ], vertices[ b + 2 ], 65 | vertices[ c ], vertices[ c + 1 ], vertices[ c + 2 ] 66 | ); 67 | 68 | } 69 | 70 | function addNormal( a, b, c ) { 71 | 72 | geometry.normals.push( 73 | normals[ a ], normals[ a + 1 ], normals[ a + 2 ], 74 | normals[ b ], normals[ b + 1 ], normals[ b + 2 ], 75 | normals[ c ], normals[ c + 1 ], normals[ c + 2 ] 76 | ); 77 | 78 | } 79 | 80 | function addUV( a, b, c ) { 81 | 82 | geometry.uvs.push( 83 | uvs[ a ], uvs[ a + 1 ], 84 | uvs[ b ], uvs[ b + 1 ], 85 | uvs[ c ], uvs[ c + 1 ] 86 | ); 87 | 88 | } 89 | 90 | function addFace( a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd ) { 91 | 92 | var ia = parseVertexIndex( a ); 93 | var ib = parseVertexIndex( b ); 94 | var ic = parseVertexIndex( c ); 95 | var id; 96 | 97 | if ( d === undefined ) { 98 | 99 | addVertex( ia, ib, ic ); 100 | 101 | } else { 102 | 103 | id = parseVertexIndex( d ); 104 | 105 | addVertex( ia, ib, id ); 106 | addVertex( ib, ic, id ); 107 | 108 | } 109 | 110 | if ( ua !== undefined ) { 111 | 112 | ia = parseUVIndex( ua ); 113 | ib = parseUVIndex( ub ); 114 | ic = parseUVIndex( uc ); 115 | 116 | if ( d === undefined ) { 117 | 118 | addUV( ia, ib, ic ); 119 | 120 | } else { 121 | 122 | id = parseUVIndex( ud ); 123 | 124 | addUV( ia, ib, id ); 125 | addUV( ib, ic, id ); 126 | 127 | } 128 | 129 | } 130 | 131 | if ( na !== undefined ) { 132 | 133 | ia = parseNormalIndex( na ); 134 | ib = parseNormalIndex( nb ); 135 | ic = parseNormalIndex( nc ); 136 | 137 | if ( d === undefined ) { 138 | 139 | addNormal( ia, ib, ic ); 140 | 141 | } else { 142 | 143 | id = parseNormalIndex( nd ); 144 | 145 | addNormal( ia, ib, id ); 146 | addNormal( ib, ic, id ); 147 | 148 | } 149 | 150 | } 151 | 152 | } 153 | 154 | // create mesh if no objects in text 155 | 156 | if ( /^o /gm.test( text ) === false ) { 157 | 158 | geometry = { 159 | vertices: [], 160 | normals: [], 161 | uvs: [] 162 | }; 163 | 164 | material = { 165 | name: '' 166 | }; 167 | 168 | object = { 169 | name: '', 170 | geometry: geometry, 171 | material: material 172 | }; 173 | 174 | objects.push( object ); 175 | 176 | } 177 | 178 | var vertices = []; 179 | var normals = []; 180 | var uvs = []; 181 | 182 | // v float float float 183 | 184 | var vertex_pattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; 185 | 186 | // vn float float float 187 | 188 | var normal_pattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; 189 | 190 | // vt float float 191 | 192 | var uv_pattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; 193 | 194 | // f vertex vertex vertex ... 195 | 196 | var face_pattern1 = /f( +-?\d+)( +-?\d+)( +-?\d+)( +-?\d+)?/; 197 | 198 | // f vertex/uv vertex/uv vertex/uv ... 199 | 200 | var face_pattern2 = /f( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))?/; 201 | 202 | // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... 203 | 204 | var face_pattern3 = /f( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))?/; 205 | 206 | // f vertex//normal vertex//normal vertex//normal ... 207 | 208 | var face_pattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/ 209 | 210 | // 211 | 212 | var lines = text.split( '\n' ); 213 | 214 | for ( var i = 0; i < lines.length; i ++ ) { 215 | 216 | var line = lines[ i ]; 217 | line = line.trim(); 218 | 219 | var result; 220 | 221 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) { 222 | 223 | continue; 224 | 225 | } else if ( ( result = vertex_pattern.exec( line ) ) !== null ) { 226 | 227 | // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 228 | 229 | vertices.push( 230 | parseFloat( result[ 1 ] ), 231 | parseFloat( result[ 2 ] ), 232 | parseFloat( result[ 3 ] ) 233 | ); 234 | 235 | } else if ( ( result = normal_pattern.exec( line ) ) !== null ) { 236 | 237 | // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 238 | 239 | normals.push( 240 | parseFloat( result[ 1 ] ), 241 | parseFloat( result[ 2 ] ), 242 | parseFloat( result[ 3 ] ) 243 | ); 244 | 245 | } else if ( ( result = uv_pattern.exec( line ) ) !== null ) { 246 | 247 | // ["vt 0.1 0.2", "0.1", "0.2"] 248 | 249 | uvs.push( 250 | parseFloat( result[ 1 ] ), 251 | parseFloat( result[ 2 ] ) 252 | ); 253 | 254 | } else if ( ( result = face_pattern1.exec( line ) ) !== null ) { 255 | 256 | // ["f 1 2 3", "1", "2", "3", undefined] 257 | 258 | addFace( 259 | result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ] 260 | ); 261 | 262 | } else if ( ( result = face_pattern2.exec( line ) ) !== null ) { 263 | 264 | // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined] 265 | 266 | addFace( 267 | result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ], 268 | result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] 269 | ); 270 | 271 | } else if ( ( result = face_pattern3.exec( line ) ) !== null ) { 272 | 273 | // ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined] 274 | 275 | addFace( 276 | result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ], 277 | result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ], 278 | result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ] 279 | ); 280 | 281 | } else if ( ( result = face_pattern4.exec( line ) ) !== null ) { 282 | 283 | // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined] 284 | 285 | addFace( 286 | result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ], 287 | undefined, undefined, undefined, undefined, 288 | result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] 289 | ); 290 | 291 | } else if ( /^o /.test( line ) ) { 292 | 293 | geometry = { 294 | vertices: [], 295 | normals: [], 296 | uvs: [] 297 | }; 298 | 299 | material = { 300 | name: '' 301 | }; 302 | 303 | object = { 304 | name: line.substring( 2 ).trim(), 305 | geometry: geometry, 306 | material: material 307 | }; 308 | 309 | objects.push( object ) 310 | 311 | } else if ( /^g /.test( line ) ) { 312 | 313 | // group 314 | 315 | } else if ( /^usemtl /.test( line ) ) { 316 | 317 | // material 318 | 319 | material.name = line.substring( 7 ).trim(); 320 | 321 | } else if ( /^mtllib /.test( line ) ) { 322 | 323 | // mtl file 324 | 325 | } else if ( /^s /.test( line ) ) { 326 | 327 | // smooth shading 328 | 329 | } else { 330 | 331 | // console.log( "THREE.OBJLoader: Unhandled line " + line ); 332 | 333 | } 334 | 335 | } 336 | 337 | var container = new THREE.Object3D(); 338 | 339 | for ( var i = 0, l = objects.length; i < l; i ++ ) { 340 | 341 | object = objects[ i ]; 342 | geometry = object.geometry; 343 | 344 | var buffergeometry = new THREE.BufferGeometry(); 345 | 346 | buffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) ); 347 | 348 | if ( geometry.normals.length > 0 ) { 349 | buffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) ); 350 | } 351 | 352 | if ( geometry.uvs.length > 0 ) { 353 | buffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) ); 354 | } 355 | 356 | material = new THREE.MeshLambertMaterial(); 357 | material.name = object.material.name; 358 | 359 | var mesh = new THREE.Mesh( buffergeometry, material ); 360 | mesh.name = object.name; 361 | 362 | container.add( mesh ); 363 | 364 | } 365 | 366 | console.timeEnd( 'OBJLoader' ); 367 | 368 | return container; 369 | 370 | } 371 | 372 | }; 373 | -------------------------------------------------------------------------------- /js/OBJMTLLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Loads a Wavefront .obj file with materials 3 | * 4 | * @author mrdoob / http://mrdoob.com/ 5 | * @author angelxuanchang 6 | */ 7 | 8 | THREE.OBJMTLLoader = function ( manager ) { 9 | 10 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 11 | 12 | }; 13 | 14 | THREE.OBJMTLLoader.prototype = { 15 | 16 | constructor: THREE.OBJMTLLoader, 17 | 18 | load: function ( url, mtlurl, onLoad, onProgress, onError ) { 19 | 20 | var scope = this; 21 | 22 | var mtlLoader = new THREE.MTLLoader( url.substr( 0, url.lastIndexOf( "/" ) + 1 ) ); 23 | mtlLoader.crossOrigin = scope.crossOrigin; 24 | mtlLoader.load( mtlurl, function ( materials ) { 25 | 26 | var materialsCreator = materials; 27 | materialsCreator.preload(); 28 | 29 | var loader = new THREE.XHRLoader( scope.manager ); 30 | loader.setCrossOrigin( scope.crossOrigin ); 31 | loader.load( url, function ( text ) { 32 | 33 | var object = scope.parse( text ); 34 | 35 | object.traverse( function ( object ) { 36 | 37 | if ( object instanceof THREE.Mesh ) { 38 | 39 | if ( object.material.name ) { 40 | 41 | var material = materialsCreator.create( object.material.name ); 42 | 43 | if ( material ) object.material = material; 44 | 45 | } 46 | 47 | } 48 | 49 | } ); 50 | 51 | onLoad( object ); 52 | 53 | }, onProgress, onError ); 54 | 55 | }, onProgress, onError ); 56 | 57 | }, 58 | 59 | /** 60 | * Parses loaded .obj file 61 | * @param data - content of .obj file 62 | * @param mtllibCallback - callback to handle mtllib declaration (optional) 63 | * @return {THREE.Object3D} - Object3D (with default material) 64 | */ 65 | 66 | parse: function ( data, mtllibCallback ) { 67 | 68 | function vector( x, y, z ) { 69 | 70 | return new THREE.Vector3( x, y, z ); 71 | 72 | } 73 | 74 | function uv( u, v ) { 75 | 76 | return new THREE.Vector2( u, v ); 77 | 78 | } 79 | 80 | function face3( a, b, c, normals ) { 81 | 82 | return new THREE.Face3( a, b, c, normals ); 83 | 84 | } 85 | 86 | var face_offset = 0; 87 | 88 | function meshN( meshName, materialName ) { 89 | 90 | if ( vertices.length > 0 ) { 91 | 92 | geometry.vertices = vertices; 93 | 94 | geometry.mergeVertices(); 95 | geometry.computeFaceNormals(); 96 | geometry.computeBoundingSphere(); 97 | 98 | object.add( mesh ); 99 | 100 | geometry = new THREE.Geometry(); 101 | mesh = new THREE.Mesh( geometry, material ); 102 | 103 | } 104 | 105 | if ( meshName !== undefined ) mesh.name = meshName; 106 | 107 | if ( materialName !== undefined ) { 108 | 109 | material = new THREE.MeshLambertMaterial(); 110 | material.name = materialName; 111 | 112 | mesh.material = material; 113 | 114 | } 115 | 116 | } 117 | 118 | var group = new THREE.Group(); 119 | var object = group; 120 | 121 | var geometry = new THREE.Geometry(); 122 | var material = new THREE.MeshLambertMaterial(); 123 | var mesh = new THREE.Mesh( geometry, material ); 124 | 125 | var vertices = []; 126 | var normals = []; 127 | var uvs = []; 128 | 129 | function add_face( a, b, c, normals_inds ) { 130 | 131 | if ( normals_inds === undefined ) { 132 | 133 | geometry.faces.push( face3( 134 | parseInt( a ) - (face_offset + 1), 135 | parseInt( b ) - (face_offset + 1), 136 | parseInt( c ) - (face_offset + 1) 137 | ) ); 138 | 139 | } else { 140 | 141 | geometry.faces.push( face3( 142 | parseInt( a ) - (face_offset + 1), 143 | parseInt( b ) - (face_offset + 1), 144 | parseInt( c ) - (face_offset + 1), 145 | [ 146 | normals[ parseInt( normals_inds[ 0 ] ) - 1 ].clone(), 147 | normals[ parseInt( normals_inds[ 1 ] ) - 1 ].clone(), 148 | normals[ parseInt( normals_inds[ 2 ] ) - 1 ].clone() 149 | ] 150 | ) ); 151 | 152 | } 153 | 154 | } 155 | 156 | function add_uvs( a, b, c ) { 157 | 158 | geometry.faceVertexUvs[ 0 ].push( [ 159 | uvs[ parseInt( a ) - 1 ].clone(), 160 | uvs[ parseInt( b ) - 1 ].clone(), 161 | uvs[ parseInt( c ) - 1 ].clone() 162 | ] ); 163 | 164 | } 165 | 166 | function handle_face_line(faces, uvs, normals_inds) { 167 | 168 | if ( faces[ 3 ] === undefined ) { 169 | 170 | add_face( faces[ 0 ], faces[ 1 ], faces[ 2 ], normals_inds ); 171 | 172 | if (!(uvs === undefined) && uvs.length > 0) { 173 | add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 2 ] ); 174 | } 175 | 176 | } else { 177 | 178 | if (!(normals_inds === undefined) && normals_inds.length > 0) { 179 | 180 | add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ], [ normals_inds[ 0 ], normals_inds[ 1 ], normals_inds[ 3 ] ]); 181 | add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ], [ normals_inds[ 1 ], normals_inds[ 2 ], normals_inds[ 3 ] ]); 182 | 183 | } else { 184 | 185 | add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ]); 186 | add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ]); 187 | 188 | } 189 | 190 | if (!(uvs === undefined) && uvs.length > 0) { 191 | 192 | add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ); 193 | add_uvs( uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ); 194 | 195 | } 196 | 197 | } 198 | 199 | } 200 | 201 | 202 | // v float float float 203 | 204 | var vertex_pattern = /v( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; 205 | 206 | // vn float float float 207 | 208 | var normal_pattern = /vn( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; 209 | 210 | // vt float float 211 | 212 | var uv_pattern = /vt( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/; 213 | 214 | // f vertex vertex vertex ... 215 | 216 | var face_pattern1 = /f( +\d+)( +\d+)( +\d+)( +\d+)?/; 217 | 218 | // f vertex/uv vertex/uv vertex/uv ... 219 | 220 | var face_pattern2 = /f( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))?/; 221 | 222 | // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... 223 | 224 | var face_pattern3 = /f( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))?/; 225 | 226 | // f vertex//normal vertex//normal vertex//normal ... 227 | 228 | var face_pattern4 = /f( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))?/ 229 | 230 | // 231 | 232 | var lines = data.split( "\n" ); 233 | 234 | for ( var i = 0; i < lines.length; i ++ ) { 235 | 236 | var line = lines[ i ]; 237 | line = line.trim(); 238 | 239 | var result; 240 | 241 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) { 242 | 243 | continue; 244 | 245 | } else if ( ( result = vertex_pattern.exec( line ) ) !== null ) { 246 | 247 | // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 248 | 249 | vertices.push( vector( 250 | parseFloat( result[ 1 ] ), 251 | parseFloat( result[ 2 ] ), 252 | parseFloat( result[ 3 ] ) 253 | ) ); 254 | 255 | } else if ( ( result = normal_pattern.exec( line ) ) !== null ) { 256 | 257 | // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 258 | 259 | normals.push( vector( 260 | parseFloat( result[ 1 ] ), 261 | parseFloat( result[ 2 ] ), 262 | parseFloat( result[ 3 ] ) 263 | ) ); 264 | 265 | } else if ( ( result = uv_pattern.exec( line ) ) !== null ) { 266 | 267 | // ["vt 0.1 0.2", "0.1", "0.2"] 268 | 269 | uvs.push( uv( 270 | parseFloat( result[ 1 ] ), 271 | parseFloat( result[ 2 ] ) 272 | ) ); 273 | 274 | } else if ( ( result = face_pattern1.exec( line ) ) !== null ) { 275 | 276 | // ["f 1 2 3", "1", "2", "3", undefined] 277 | 278 | handle_face_line([ result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ] ]); 279 | 280 | } else if ( ( result = face_pattern2.exec( line ) ) !== null ) { 281 | 282 | // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined] 283 | 284 | handle_face_line( 285 | [ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces 286 | [ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //uv 287 | ); 288 | 289 | } else if ( ( result = face_pattern3.exec( line ) ) !== null ) { 290 | 291 | // ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined] 292 | 293 | handle_face_line( 294 | [ result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ] ], //faces 295 | [ result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ] ], //uv 296 | [ result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ] ] //normal 297 | ); 298 | 299 | } else if ( ( result = face_pattern4.exec( line ) ) !== null ) { 300 | 301 | // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined] 302 | 303 | handle_face_line( 304 | [ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces 305 | [ ], //uv 306 | [ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //normal 307 | ); 308 | 309 | } else if ( /^o /.test( line ) ) { 310 | 311 | // object 312 | 313 | meshN(); 314 | face_offset = face_offset + vertices.length; 315 | vertices = []; 316 | object = new THREE.Object3D(); 317 | object.name = line.substring( 2 ).trim(); 318 | group.add( object ); 319 | 320 | } else if ( /^g /.test( line ) ) { 321 | 322 | // group 323 | 324 | meshN( line.substring( 2 ).trim(), undefined ); 325 | 326 | } else if ( /^usemtl /.test( line ) ) { 327 | 328 | // material 329 | 330 | meshN( undefined, line.substring( 7 ).trim() ); 331 | 332 | } else if ( /^mtllib /.test( line ) ) { 333 | 334 | // mtl file 335 | 336 | if ( mtllibCallback ) { 337 | 338 | var mtlfile = line.substring( 7 ); 339 | mtlfile = mtlfile.trim(); 340 | mtllibCallback( mtlfile ); 341 | 342 | } 343 | 344 | } else if ( /^s /.test( line ) ) { 345 | 346 | // Smooth shading 347 | 348 | } else { 349 | 350 | console.log( "THREE.OBJMTLLoader: Unhandled line " + line ); 351 | 352 | } 353 | 354 | } 355 | 356 | //Add last object 357 | meshN(undefined, undefined); 358 | 359 | return group; 360 | 361 | } 362 | 363 | }; 364 | 365 | THREE.EventDispatcher.prototype.apply( THREE.OBJMTLLoader.prototype ); 366 | -------------------------------------------------------------------------------- /js/Sidebar.LightBaking.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | Sidebar.LightBaking = function ( editor ) { 6 | 7 | 8 | function addSelectOptions( params ) { 9 | var options = {}; 10 | var key; 11 | 12 | for ( key in params.types ) { 13 | 14 | options[ key ] = key; 15 | 16 | } 17 | 18 | var rowPanel = new UI.Panel(); 19 | var selops = new UI.Select().setOptions( options ).setWidth( params.selopWidth ).onChange( function () { 20 | 21 | editor.config.setKey( params.path, this.getValue() ); 22 | 23 | } ); 24 | 25 | rowPanel.add( new UI.Text( params.uiText ).setWidth( params.uiWidth ) ); 26 | rowPanel.add( selops ); 27 | 28 | container.add( rowPanel ); 29 | 30 | if ( editor.config.getKey( params.path ) !== undefined ) { 31 | 32 | selops.setValue( editor.config.getKey( params.path ) ); 33 | 34 | } else { 35 | 36 | editor.config.setKey( params.path, params.default ); 37 | 38 | } 39 | 40 | } 41 | 42 | var signals = editor.signals; 43 | 44 | 45 | var container = new UI.CollapsiblePanel(); 46 | container.setCollapsed( editor.config.getKey( 'ui/sidebar/project/collapsed' ) ); 47 | container.onCollapsedChange( function ( boolean ) { 48 | 49 | editor.config.setKey( 'ui/sidebar/project/collapsed', boolean ); 50 | 51 | } ); 52 | 53 | container.addStatic( new UI.Text( 'LIGHT BAKING' ) ); 54 | container.add( new UI.Break() ); 55 | 56 | var appModeTypes = { 57 | 'Single Thread': THREE.LightBaking.ApplicationExecutionEnum.SINGLETHREADED, 58 | 'Asynchronous': THREE.LightBaking.ApplicationExecutionEnum.SINGLETHREADED, 59 | 'Multi Threaded': THREE.LightBaking.ApplicationExecutionEnum.MULTITHREADED 60 | }; 61 | 62 | var bakingMethodTypes = { 63 | 'Path Tracing': THREE.LightBaking.BakingMethodEnum.PATHTRACING, 64 | 'Two Pass Method': THREE.LightBaking.BakingMethodEnum.TWOPASS, 65 | }; 66 | 67 | var shadingTypes = { 68 | 'Flat': THREE.LightBaking.ShadingEnum.FLAT, 69 | 'Phong': THREE.LightBaking.ShadingEnum.PHONG, 70 | 'FlatFastMethod': THREE.ightBaking.ShadingEnum.FLATFAST, 71 | }; 72 | 73 | var softshadowTypes = { 74 | 'false': false, 75 | 'true': true, 76 | }; 77 | 78 | var uvMethodTypes = { 79 | 'Uniform': THREE.LightBaking.UVMethodEnum.UNIFORMCENTERED, 80 | 'Packed': THREE.LightBaking.UVMethodEnum.PACKED, 81 | }; 82 | 83 | var filterTypes = { 84 | 'None': THREE.LightBaking.FilterEnum.NONE, 85 | 'Gauss': THREE.LightBaking.FilterEnum.GAUSS, 86 | 'Box': THREE.LightBaking.FilterEnum.BOX, 87 | }; 88 | 89 | addSelectOptions( { 90 | path: 'lightbaking/appMode', 91 | types: appModeTypes, 92 | default: "Multi Threaded", 93 | selopWidth: '100px', 94 | uiText: 'Execution Model', 95 | uiWidth: '150px' 96 | } ); 97 | 98 | // TextureSize 99 | var textureSizeRow = new UI.Panel(); 100 | var textureSize = new UI.Input().setWidth( '100px' ).setFontSize( '12px' ).onChange( function () { 101 | 102 | editor.config.setKey( 'lightbaking/textureSize', this.getValue() ); 103 | 104 | } ); 105 | 106 | if ( textureSize.getValue() === "undefined" ) { 107 | 108 | var textureSizeStored = editor.config.getKey( 'lightbaking/textureSize' ); 109 | textureSize.setValue( textureSizeStored !== undefined ? textureSizeStored : 512 ); 110 | 111 | } 112 | 113 | textureSizeRow.add( new UI.Text( 'Texturesize' ).setWidth( '150px' ) ); 114 | textureSizeRow.add( textureSize ); 115 | 116 | container.add( textureSizeRow ); 117 | 118 | // Samples 119 | var samplesNameRow = new UI.Panel(); 120 | var samples = new UI.Input().setWidth( '100px' ).setFontSize( '12px' ).onChange( function () { 121 | 122 | editor.config.setKey( 'lightbaking/samples', this.getValue() ); 123 | 124 | } ); 125 | 126 | if ( samples.getValue() === "undefined" ) { 127 | 128 | var samplesStored = editor.config.getKey( 'lightbaking/samples' ); 129 | samples.setValue( samplesStored !== undefined ? samplesStored : 2 ); 130 | 131 | } 132 | 133 | samplesNameRow.add( new UI.Text( 'Samples' ).setWidth( '150px' ) ); 134 | samplesNameRow.add( samples ); 135 | 136 | container.add( samplesNameRow ); 137 | 138 | // recursionLevel 139 | var recursionLevelRow = new UI.Panel(); 140 | var recursionLevel = new UI.Input().setWidth( '100px' ).setFontSize( '12px' ).onChange( function () { 141 | 142 | editor.config.setKey( 'lightbaking/recursionLevel', this.getValue() ); 143 | 144 | } ); 145 | 146 | if ( recursionLevel.getValue() === "undefined" ) { 147 | 148 | var recursionLevelStored = editor.config.getKey( 'lightbaking/recursionLevel' ); 149 | recursionLevel.setValue( recursionLevelStored !== undefined ? recursionLevelStored : 2 ); 150 | 151 | } 152 | 153 | recursionLevelRow.add( new UI.Text( 'Recursion level' ).setWidth( '150px' ) ); 154 | recursionLevelRow.add( recursionLevel ); 155 | 156 | container.add( recursionLevelRow ); 157 | 158 | 159 | addSelectOptions( { 160 | path: 'lightbaking/shading', 161 | types: shadingTypes, 162 | default: "Flat", 163 | selopWidth: '100px', 164 | uiText: 'Interpolation', 165 | uiWidth: '150px' 166 | } ); 167 | 168 | addSelectOptions( { 169 | path: 'lightbaking/softshadows', 170 | types: softshadowTypes, 171 | default: "Flat", 172 | selopWidth: '100px', 173 | uiText: 'Softshadows', 174 | uiWidth: '150px' 175 | } ); 176 | 177 | addSelectOptions( { 178 | path: 'lightbaking/uvMethod', 179 | types: uvMethodTypes, 180 | default: "Packed", 181 | selopWidth: '100px', 182 | uiText: 'UV Method', 183 | uiWidth: '150px' 184 | } ); 185 | 186 | addSelectOptions( { 187 | path: 'lightbaking/filter', 188 | types: filterTypes, 189 | default: "None", 190 | selopWidth: '100px', 191 | uiText: 'IP-Filter', 192 | uiWidth: '150px' 193 | } ); 194 | 195 | 196 | var runButton = new UI.Button().setLabel( 'Run' ).onClick( function () { 197 | 198 | debugger; 199 | 200 | var params = {}; 201 | 202 | var textureSizeP = editor.config.getKey( 'lightbaking/textureSize' ); 203 | 204 | params.resetUserData = true; 205 | params.debugText = true; 206 | params.workerSource = "../../js/LightBakingWorker.js"; 207 | params.appMode = appModeTypes[ editor.config.getKey( 'lightbaking/appMode' ) ]; 208 | params.samples = editor.config.getKey( 'lightbaking/samples' ); 209 | params.pathTracingRecLevel = editor.config.getKey( 'lightbaking/recursionLevel' ); 210 | params.giIntensity = 2; 211 | params.shading = shadingTypes[ editor.config.getKey( 'lightbaking/shading' ) ]; 212 | params.softShadows = softshadowTypes[ editor.config.getKey( 'lightbaking/softshadows' ) ]; 213 | params.postProcessingFilter = filterTypes[ editor.config.getKey( 'lightbaking/filter' ) ]; 214 | params.textureWidth = textureSizeP; 215 | params.textureHeight = textureSizeP; 216 | params.uvMethod = uvMethodTypes[ editor.config.getKey( 'lightbaking/uvMethod' ) ]; 217 | params.scene = editor.scene; 218 | 219 | var lightBaking = new THREE.LightBaking( params ); 220 | 221 | document.title = "Baking in Progress."; 222 | 223 | lightBaking.run( function () { 224 | 225 | var baked = 0; 226 | 227 | lightBaking.setOnMeshBaked( function () { 228 | 229 | document.title = "Mesh " + baked++ + " Baked"; 230 | 231 | // TODO force udpate! 232 | //updateRenderer(); 233 | 234 | } ); 235 | 236 | lightBaking.setAfterExecuted( function () { 237 | 238 | document.title = baked + " Meshes baked."; 239 | 240 | } ); 241 | 242 | } ); 243 | 244 | } ); 245 | 246 | container.add( runButton ); 247 | 248 | return container; 249 | 250 | }; 251 | -------------------------------------------------------------------------------- /js/TrackballControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Eberhard Graether / http://egraether.com/ 3 | * @author Mark Lundin / http://mark-lundin.com 4 | */ 5 | 6 | THREE.TrackballControls = function ( object, domElement ) { 7 | 8 | var _this = this; 9 | var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }; 10 | 11 | this.object = object; 12 | this.domElement = ( domElement !== undefined ) ? domElement : document; 13 | 14 | // API 15 | 16 | this.enabled = true; 17 | 18 | this.screen = { left: 0, top: 0, width: 0, height: 0 }; 19 | 20 | this.rotateSpeed = 1.0; 21 | this.zoomSpeed = 1.2; 22 | this.panSpeed = 0.3; 23 | 24 | this.noRotate = false; 25 | this.noZoom = false; 26 | this.noPan = false; 27 | this.noRoll = false; 28 | 29 | this.staticMoving = false; 30 | this.dynamicDampingFactor = 0.2; 31 | 32 | this.minDistance = 0; 33 | this.maxDistance = Infinity; 34 | 35 | this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; 36 | 37 | // internals 38 | 39 | this.target = new THREE.Vector3(); 40 | 41 | var EPS = 0.000001; 42 | 43 | var lastPosition = new THREE.Vector3(); 44 | 45 | var _state = STATE.NONE, 46 | _prevState = STATE.NONE, 47 | 48 | _eye = new THREE.Vector3(), 49 | 50 | _rotateStart = new THREE.Vector3(), 51 | _rotateEnd = new THREE.Vector3(), 52 | 53 | _zoomStart = new THREE.Vector2(), 54 | _zoomEnd = new THREE.Vector2(), 55 | 56 | _touchZoomDistanceStart = 0, 57 | _touchZoomDistanceEnd = 0, 58 | 59 | _panStart = new THREE.Vector2(), 60 | _panEnd = new THREE.Vector2(); 61 | 62 | // for reset 63 | 64 | this.target0 = this.target.clone(); 65 | this.position0 = this.object.position.clone(); 66 | this.up0 = this.object.up.clone(); 67 | 68 | // events 69 | 70 | var changeEvent = { type: 'change' }; 71 | var startEvent = { type: 'start'}; 72 | var endEvent = { type: 'end'}; 73 | 74 | 75 | // methods 76 | 77 | this.handleResize = function () { 78 | 79 | if ( this.domElement === document ) { 80 | 81 | this.screen.left = 0; 82 | this.screen.top = 0; 83 | this.screen.width = window.innerWidth; 84 | this.screen.height = window.innerHeight; 85 | 86 | } else { 87 | 88 | var box = this.domElement.getBoundingClientRect(); 89 | // adjustments come from similar code in the jquery offset() function 90 | var d = this.domElement.ownerDocument.documentElement; 91 | this.screen.left = box.left + window.pageXOffset - d.clientLeft; 92 | this.screen.top = box.top + window.pageYOffset - d.clientTop; 93 | this.screen.width = box.width; 94 | this.screen.height = box.height; 95 | 96 | } 97 | 98 | }; 99 | 100 | this.handleEvent = function ( event ) { 101 | 102 | if ( typeof this[ event.type ] == 'function' ) { 103 | 104 | this[ event.type ]( event ); 105 | 106 | } 107 | 108 | }; 109 | 110 | var getMouseOnScreen = ( function () { 111 | 112 | var vector = new THREE.Vector2(); 113 | 114 | return function ( pageX, pageY ) { 115 | 116 | vector.set( 117 | ( pageX - _this.screen.left ) / _this.screen.width, 118 | ( pageY - _this.screen.top ) / _this.screen.height 119 | ); 120 | 121 | return vector; 122 | 123 | }; 124 | 125 | }() ); 126 | 127 | var getMouseProjectionOnBall = ( function () { 128 | 129 | var vector = new THREE.Vector3(); 130 | var objectUp = new THREE.Vector3(); 131 | var mouseOnBall = new THREE.Vector3(); 132 | 133 | return function ( pageX, pageY ) { 134 | 135 | mouseOnBall.set( 136 | ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5), 137 | ( _this.screen.height * 0.5 + _this.screen.top - pageY ) / (_this.screen.height*.5), 138 | 0.0 139 | ); 140 | 141 | var length = mouseOnBall.length(); 142 | 143 | if ( _this.noRoll ) { 144 | 145 | if ( length < Math.SQRT1_2 ) { 146 | 147 | mouseOnBall.z = Math.sqrt( 1.0 - length*length ); 148 | 149 | } else { 150 | 151 | mouseOnBall.z = .5 / length; 152 | 153 | } 154 | 155 | } else if ( length > 1.0 ) { 156 | 157 | mouseOnBall.normalize(); 158 | 159 | } else { 160 | 161 | mouseOnBall.z = Math.sqrt( 1.0 - length * length ); 162 | 163 | } 164 | 165 | _eye.copy( _this.object.position ).sub( _this.target ); 166 | 167 | vector.copy( _this.object.up ).setLength( mouseOnBall.y ) 168 | vector.add( objectUp.copy( _this.object.up ).cross( _eye ).setLength( mouseOnBall.x ) ); 169 | vector.add( _eye.setLength( mouseOnBall.z ) ); 170 | 171 | return vector; 172 | 173 | }; 174 | 175 | }() ); 176 | 177 | this.rotateCamera = (function(){ 178 | 179 | var axis = new THREE.Vector3(), 180 | quaternion = new THREE.Quaternion(); 181 | 182 | 183 | return function () { 184 | 185 | var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() ); 186 | 187 | if ( angle ) { 188 | 189 | axis.crossVectors( _rotateStart, _rotateEnd ).normalize(); 190 | 191 | angle *= _this.rotateSpeed; 192 | 193 | quaternion.setFromAxisAngle( axis, -angle ); 194 | 195 | _eye.applyQuaternion( quaternion ); 196 | _this.object.up.applyQuaternion( quaternion ); 197 | 198 | _rotateEnd.applyQuaternion( quaternion ); 199 | 200 | if ( _this.staticMoving ) { 201 | 202 | _rotateStart.copy( _rotateEnd ); 203 | 204 | } else { 205 | 206 | quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) ); 207 | _rotateStart.applyQuaternion( quaternion ); 208 | 209 | } 210 | 211 | } 212 | } 213 | 214 | }()); 215 | 216 | this.zoomCamera = function () { 217 | 218 | if ( _state === STATE.TOUCH_ZOOM_PAN ) { 219 | 220 | var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; 221 | _touchZoomDistanceStart = _touchZoomDistanceEnd; 222 | _eye.multiplyScalar( factor ); 223 | 224 | } else { 225 | 226 | var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed; 227 | 228 | if ( factor !== 1.0 && factor > 0.0 ) { 229 | 230 | _eye.multiplyScalar( factor ); 231 | 232 | if ( _this.staticMoving ) { 233 | 234 | _zoomStart.copy( _zoomEnd ); 235 | 236 | } else { 237 | 238 | _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; 239 | 240 | } 241 | 242 | } 243 | 244 | } 245 | 246 | }; 247 | 248 | this.panCamera = (function(){ 249 | 250 | var mouseChange = new THREE.Vector2(), 251 | objectUp = new THREE.Vector3(), 252 | pan = new THREE.Vector3(); 253 | 254 | return function () { 255 | 256 | mouseChange.copy( _panEnd ).sub( _panStart ); 257 | 258 | if ( mouseChange.lengthSq() ) { 259 | 260 | mouseChange.multiplyScalar( _eye.length() * _this.panSpeed ); 261 | 262 | pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x ); 263 | pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) ); 264 | 265 | _this.object.position.add( pan ); 266 | _this.target.add( pan ); 267 | 268 | if ( _this.staticMoving ) { 269 | 270 | _panStart.copy( _panEnd ); 271 | 272 | } else { 273 | 274 | _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) ); 275 | 276 | } 277 | 278 | } 279 | } 280 | 281 | }()); 282 | 283 | this.checkDistances = function () { 284 | 285 | if ( !_this.noZoom || !_this.noPan ) { 286 | 287 | if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) { 288 | 289 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) ); 290 | 291 | } 292 | 293 | if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) { 294 | 295 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) ); 296 | 297 | } 298 | 299 | } 300 | 301 | }; 302 | 303 | this.update = function () { 304 | 305 | _eye.subVectors( _this.object.position, _this.target ); 306 | 307 | if ( !_this.noRotate ) { 308 | 309 | _this.rotateCamera(); 310 | 311 | } 312 | 313 | if ( !_this.noZoom ) { 314 | 315 | _this.zoomCamera(); 316 | 317 | } 318 | 319 | if ( !_this.noPan ) { 320 | 321 | _this.panCamera(); 322 | 323 | } 324 | 325 | _this.object.position.addVectors( _this.target, _eye ); 326 | 327 | _this.checkDistances(); 328 | 329 | _this.object.lookAt( _this.target ); 330 | 331 | if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) { 332 | 333 | _this.dispatchEvent( changeEvent ); 334 | 335 | lastPosition.copy( _this.object.position ); 336 | 337 | } 338 | 339 | }; 340 | 341 | this.reset = function () { 342 | 343 | _state = STATE.NONE; 344 | _prevState = STATE.NONE; 345 | 346 | _this.target.copy( _this.target0 ); 347 | _this.object.position.copy( _this.position0 ); 348 | _this.object.up.copy( _this.up0 ); 349 | 350 | _eye.subVectors( _this.object.position, _this.target ); 351 | 352 | _this.object.lookAt( _this.target ); 353 | 354 | _this.dispatchEvent( changeEvent ); 355 | 356 | lastPosition.copy( _this.object.position ); 357 | 358 | }; 359 | 360 | // listeners 361 | 362 | function keydown( event ) { 363 | 364 | if ( _this.enabled === false ) return; 365 | 366 | window.removeEventListener( 'keydown', keydown ); 367 | 368 | _prevState = _state; 369 | 370 | if ( _state !== STATE.NONE ) { 371 | 372 | return; 373 | 374 | } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) { 375 | 376 | _state = STATE.ROTATE; 377 | 378 | } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) { 379 | 380 | _state = STATE.ZOOM; 381 | 382 | } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) { 383 | 384 | _state = STATE.PAN; 385 | 386 | } 387 | 388 | } 389 | 390 | function keyup( event ) { 391 | 392 | if ( _this.enabled === false ) return; 393 | 394 | _state = _prevState; 395 | 396 | window.addEventListener( 'keydown', keydown, false ); 397 | 398 | } 399 | 400 | function mousedown( event ) { 401 | 402 | if ( _this.enabled === false ) return; 403 | 404 | event.preventDefault(); 405 | event.stopPropagation(); 406 | 407 | if ( _state === STATE.NONE ) { 408 | 409 | _state = event.button; 410 | 411 | } 412 | 413 | if ( _state === STATE.ROTATE && !_this.noRotate ) { 414 | 415 | _rotateStart.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) ); 416 | _rotateEnd.copy( _rotateStart ); 417 | 418 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) { 419 | 420 | _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 421 | _zoomEnd.copy(_zoomStart); 422 | 423 | } else if ( _state === STATE.PAN && !_this.noPan ) { 424 | 425 | _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 426 | _panEnd.copy(_panStart) 427 | 428 | } 429 | 430 | document.addEventListener( 'mousemove', mousemove, false ); 431 | document.addEventListener( 'mouseup', mouseup, false ); 432 | 433 | _this.dispatchEvent( startEvent ); 434 | 435 | } 436 | 437 | function mousemove( event ) { 438 | 439 | if ( _this.enabled === false ) return; 440 | 441 | event.preventDefault(); 442 | event.stopPropagation(); 443 | 444 | if ( _state === STATE.ROTATE && !_this.noRotate ) { 445 | 446 | _rotateEnd.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) ); 447 | 448 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) { 449 | 450 | _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 451 | 452 | } else if ( _state === STATE.PAN && !_this.noPan ) { 453 | 454 | _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 455 | 456 | } 457 | 458 | } 459 | 460 | function mouseup( event ) { 461 | 462 | if ( _this.enabled === false ) return; 463 | 464 | event.preventDefault(); 465 | event.stopPropagation(); 466 | 467 | _state = STATE.NONE; 468 | 469 | document.removeEventListener( 'mousemove', mousemove ); 470 | document.removeEventListener( 'mouseup', mouseup ); 471 | _this.dispatchEvent( endEvent ); 472 | 473 | } 474 | 475 | function mousewheel( event ) { 476 | 477 | if ( _this.enabled === false ) return; 478 | 479 | event.preventDefault(); 480 | event.stopPropagation(); 481 | 482 | var delta = 0; 483 | 484 | if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 485 | 486 | delta = event.wheelDelta / 40; 487 | 488 | } else if ( event.detail ) { // Firefox 489 | 490 | delta = - event.detail / 3; 491 | 492 | } 493 | 494 | _zoomStart.y += delta * 0.01; 495 | _this.dispatchEvent( startEvent ); 496 | _this.dispatchEvent( endEvent ); 497 | 498 | } 499 | 500 | function touchstart( event ) { 501 | 502 | if ( _this.enabled === false ) return; 503 | 504 | switch ( event.touches.length ) { 505 | 506 | case 1: 507 | _state = STATE.TOUCH_ROTATE; 508 | _rotateStart.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 509 | _rotateEnd.copy( _rotateStart ); 510 | break; 511 | 512 | case 2: 513 | _state = STATE.TOUCH_ZOOM_PAN; 514 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 515 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 516 | _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); 517 | 518 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; 519 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; 520 | _panStart.copy( getMouseOnScreen( x, y ) ); 521 | _panEnd.copy( _panStart ); 522 | break; 523 | 524 | default: 525 | _state = STATE.NONE; 526 | 527 | } 528 | _this.dispatchEvent( startEvent ); 529 | 530 | 531 | } 532 | 533 | function touchmove( event ) { 534 | 535 | if ( _this.enabled === false ) return; 536 | 537 | event.preventDefault(); 538 | event.stopPropagation(); 539 | 540 | switch ( event.touches.length ) { 541 | 542 | case 1: 543 | _rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 544 | break; 545 | 546 | case 2: 547 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 548 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 549 | _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ); 550 | 551 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; 552 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; 553 | _panEnd.copy( getMouseOnScreen( x, y ) ); 554 | break; 555 | 556 | default: 557 | _state = STATE.NONE; 558 | 559 | } 560 | 561 | } 562 | 563 | function touchend( event ) { 564 | 565 | if ( _this.enabled === false ) return; 566 | 567 | switch ( event.touches.length ) { 568 | 569 | case 1: 570 | _rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 571 | _rotateStart.copy( _rotateEnd ); 572 | break; 573 | 574 | case 2: 575 | _touchZoomDistanceStart = _touchZoomDistanceEnd = 0; 576 | 577 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; 578 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; 579 | _panEnd.copy( getMouseOnScreen( x, y ) ); 580 | _panStart.copy( _panEnd ); 581 | break; 582 | 583 | } 584 | 585 | _state = STATE.NONE; 586 | _this.dispatchEvent( endEvent ); 587 | 588 | } 589 | 590 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); 591 | 592 | this.domElement.addEventListener( 'mousedown', mousedown, false ); 593 | 594 | this.domElement.addEventListener( 'mousewheel', mousewheel, false ); 595 | this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox 596 | 597 | this.domElement.addEventListener( 'touchstart', touchstart, false ); 598 | this.domElement.addEventListener( 'touchend', touchend, false ); 599 | this.domElement.addEventListener( 'touchmove', touchmove, false ); 600 | 601 | window.addEventListener( 'keydown', keydown, false ); 602 | window.addEventListener( 'keyup', keyup, false ); 603 | 604 | this.handleResize(); 605 | 606 | // force an update at start 607 | this.update(); 608 | 609 | }; 610 | 611 | THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 612 | THREE.TrackballControls.prototype.constructor = THREE.TrackballControls; 613 | -------------------------------------------------------------------------------- /js/dat.gui.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * dat-gui JavaScript Controller Library 3 | * https://github.com/dataarts/dat.gui 4 | * 5 | * Copyright 2016 Data Arts Team, Google Creative Lab 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | */ 13 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.dat=t():e.dat=t()}(this,function(){return function(e){function t(o){if(n[o])return n[o].exports;var i=n[o]={exports:{},id:o,loaded:!1};return e[o].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}var i=n(1),r=o(i);e.exports=r["default"]},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0;var i=n(2),r=o(i),a=n(6),l=o(a),s=n(3),u=o(s),d=n(7),c=o(d),f=n(8),_=o(f),p=n(10),h=o(p),m=n(11),b=o(m),g=n(12),v=o(g),y=n(13),w=o(y),x=n(14),E=o(x),C=n(15),A=o(C),S=n(16),k=o(S),O=n(9),T=o(O),R=n(17),L=o(R);t["default"]={color:{Color:r["default"],math:l["default"],interpret:u["default"]},controllers:{Controller:c["default"],BooleanController:_["default"],OptionController:h["default"],StringController:b["default"],NumberController:v["default"],NumberControllerBox:w["default"],NumberControllerSlider:E["default"],FunctionController:A["default"],ColorController:k["default"]},dom:{dom:T["default"]},gui:{GUI:L["default"]},GUI:L["default"]}},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t,n){Object.defineProperty(e,t,{get:function(){return"RGB"===this.__state.space?this.__state[t]:(h.recalculateRGB(this,t,n),this.__state[t])},set:function(e){"RGB"!==this.__state.space&&(h.recalculateRGB(this,t,n),this.__state.space="RGB"),this.__state[t]=e}})}function a(e,t){Object.defineProperty(e,t,{get:function(){return"HSV"===this.__state.space?this.__state[t]:(h.recalculateHSV(this),this.__state[t])},set:function(e){"HSV"!==this.__state.space&&(h.recalculateHSV(this),this.__state.space="HSV"),this.__state[t]=e}})}t.__esModule=!0;var l=n(3),s=o(l),u=n(6),d=o(u),c=n(4),f=o(c),_=n(5),p=o(_),h=function(){function e(){if(i(this,e),this.__state=s["default"].apply(this,arguments),this.__state===!1)throw new Error("Failed to interpret color arguments");this.__state.a=this.__state.a||1}return e.prototype.toString=function(){return(0,f["default"])(this)},e.prototype.toHexString=function(){return(0,f["default"])(this,!0)},e.prototype.toOriginal=function(){return this.__state.conversion.write(this)},e}();h.recalculateRGB=function(e,t,n){if("HEX"===e.__state.space)e.__state[t]=d["default"].component_from_hex(e.__state.hex,n);else{if("HSV"!==e.__state.space)throw new Error("Corrupted color state");p["default"].extend(e.__state,d["default"].hsv_to_rgb(e.__state.h,e.__state.s,e.__state.v))}},h.recalculateHSV=function(e){var t=d["default"].rgb_to_hsv(e.r,e.g,e.b);p["default"].extend(e.__state,{s:t.s,v:t.v}),p["default"].isNaN(t.h)?p["default"].isUndefined(e.__state.h)&&(e.__state.h=0):e.__state.h=t.h},h.COMPONENTS=["r","g","b","h","s","v","hex","a"],r(h.prototype,"r",2),r(h.prototype,"g",1),r(h.prototype,"b",0),a(h.prototype,"h"),a(h.prototype,"s"),a(h.prototype,"v"),Object.defineProperty(h.prototype,"a",{get:function(){return this.__state.a},set:function(e){this.__state.a=e}}),Object.defineProperty(h.prototype,"hex",{get:function(){return"HEX"!==!this.__state.space&&(this.__state.hex=d["default"].rgb_to_hex(this.r,this.g,this.b)),this.__state.hex},set:function(e){this.__state.space="HEX",this.__state.hex=e}}),t["default"]=h},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0;var i=n(4),r=o(i),a=n(5),l=o(a),s=[{litmus:l["default"].isString,conversions:{THREE_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString()+t[1].toString()+t[2].toString()+t[2].toString()+t[3].toString()+t[3].toString(),0)}},write:r["default"]},SIX_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9]{6})$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString(),0)}},write:r["default"]},CSS_RGB:{read:function(e){var t=e.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3])}},write:r["default"]},CSS_RGBA:{read:function(e){var t=e.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3]),a:parseFloat(t[4])}},write:r["default"]}}},{litmus:l["default"].isNumber,conversions:{HEX:{read:function(e){return{space:"HEX",hex:e,conversionName:"HEX"}},write:function(e){return e.hex}}}},{litmus:l["default"].isArray,conversions:{RGB_ARRAY:{read:function(e){return 3===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2]}},write:function(e){return[e.r,e.g,e.b]}},RGBA_ARRAY:{read:function(e){return 4===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2],a:e[3]}},write:function(e){return[e.r,e.g,e.b,e.a]}}}},{litmus:l["default"].isObject,conversions:{RGBA_OBJ:{read:function(e){return!!(l["default"].isNumber(e.r)&&l["default"].isNumber(e.g)&&l["default"].isNumber(e.b)&&l["default"].isNumber(e.a))&&{space:"RGB",r:e.r,g:e.g,b:e.b,a:e.a}},write:function(e){return{r:e.r,g:e.g,b:e.b,a:e.a}}},RGB_OBJ:{read:function(e){return!!(l["default"].isNumber(e.r)&&l["default"].isNumber(e.g)&&l["default"].isNumber(e.b))&&{space:"RGB",r:e.r,g:e.g,b:e.b}},write:function(e){return{r:e.r,g:e.g,b:e.b}}},HSVA_OBJ:{read:function(e){return!!(l["default"].isNumber(e.h)&&l["default"].isNumber(e.s)&&l["default"].isNumber(e.v)&&l["default"].isNumber(e.a))&&{space:"HSV",h:e.h,s:e.s,v:e.v,a:e.a}},write:function(e){return{h:e.h,s:e.s,v:e.v,a:e.a}}},HSV_OBJ:{read:function(e){return!!(l["default"].isNumber(e.h)&&l["default"].isNumber(e.s)&&l["default"].isNumber(e.v))&&{space:"HSV",h:e.h,s:e.s,v:e.v}},write:function(e){return{h:e.h,s:e.s,v:e.v}}}}}],u=void 0,d=void 0,c=function(){d=!1;var e=arguments.length>1?l["default"].toArray(arguments):arguments[0];return l["default"].each(s,function(t){if(t.litmus(e))return l["default"].each(t.conversions,function(t,n){if(u=t.read(e),d===!1&&u!==!1)return d=u,u.conversionName=n,u.conversion=t,l["default"].BREAK}),l["default"].BREAK}),d};t["default"]=c},function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e,t){var n=e.__state.conversionName.toString(),o=Math.round(e.r),i=Math.round(e.g),r=Math.round(e.b),a=e.a,l=Math.round(e.h),s=e.s.toFixed(1),u=e.v.toFixed(1);if(t||"THREE_CHAR_HEX"===n||"SIX_CHAR_HEX"===n){for(var d=e.hex.toString(16);d.length<6;)d="0"+d;return"#"+d}return"CSS_RGB"===n?"rgb("+o+","+i+","+r+")":"CSS_RGBA"===n?"rgba("+o+","+i+","+r+","+a+")":"HEX"===n?"0x"+e.hex.toString(16):"RGB_ARRAY"===n?"["+o+","+i+","+r+"]":"RGBA_ARRAY"===n?"["+o+","+i+","+r+","+a+"]":"RGB_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+"}":"RGBA_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+",a:"+a+"}":"HSV_OBJ"===n?"{h:"+l+",s:"+s+",v:"+u+"}":"HSVA_OBJ"===n?"{h:"+l+",s:"+s+",v:"+u+",a:"+a+"}":"unknown format"}},function(e,t){"use strict";t.__esModule=!0;var n=Array.prototype.forEach,o=Array.prototype.slice,i={BREAK:{},extend:function(e){return this.each(o.call(arguments,1),function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(t[n])||(e[n]=t[n])}.bind(this))},this),e},defaults:function(e){return this.each(o.call(arguments,1),function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(e[n])&&(e[n]=t[n])}.bind(this))},this),e},compose:function(){var e=o.call(arguments);return function(){for(var t=o.call(arguments),n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},each:function(e,t,o){if(e)if(n&&e.forEach&&e.forEach===n)e.forEach(t,o);else if(e.length===e.length+0){var i=void 0,r=void 0;for(i=0,r=e.length;i>8*t&255},hex_with_component:function(e,t,o){return o<<(n=8*t)|e&~(255<-1?t.length-t.indexOf(".")-1:0}t.__esModule=!0;var s=n(7),u=o(s),d=n(5),c=o(d),f=function(e){function t(n,o,a){i(this,t);var s=r(this,e.call(this,n,o)),u=a||{};return s.__min=u.min,s.__max=u.max,s.__step=u.step,c["default"].isUndefined(s.__step)?0===s.initialValue?s.__impliedStep=1:s.__impliedStep=Math.pow(10,Math.floor(Math.log(Math.abs(s.initialValue))/Math.LN10))/10:s.__impliedStep=s.__step,s.__precision=l(s.__impliedStep),s}return a(t,e),t.prototype.setValue=function(t){var n=t;return void 0!==this.__min&&nthis.__max&&(n=this.__max),void 0!==this.__step&&n%this.__step!==0&&(n=Math.round(n/this.__step)*this.__step),e.prototype.setValue.call(this,n)},t.prototype.min=function(e){return this.__min=e,this},t.prototype.max=function(e){return this.__max=e,this},t.prototype.step=function(e){return this.__step=e,this.__impliedStep=e,this.__precision=l(e),this},t}(u["default"]);t["default"]=f},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t){var n=Math.pow(10,t);return Math.round(e*n)/n}t.__esModule=!0;var s=n(12),u=o(s),d=n(9),c=o(d),f=n(5),_=o(f),p=function(e){function t(n,o,a){function l(){var e=parseFloat(m.__input.value);_["default"].isNaN(e)||m.setValue(e)}function s(){m.__onFinishChange&&m.__onFinishChange.call(m,m.getValue())}function u(){s()}function d(e){var t=b-e.clientY;m.setValue(m.getValue()+t*m.__impliedStep),b=e.clientY}function f(){c["default"].unbind(window,"mousemove",d),c["default"].unbind(window,"mouseup",f),s()}function p(e){c["default"].bind(window,"mousemove",d),c["default"].bind(window,"mouseup",f),b=e.clientY}i(this,t);var h=r(this,e.call(this,n,o,a));h.__truncationSuspended=!1;var m=h,b=void 0;return h.__input=document.createElement("input"),h.__input.setAttribute("type","text"),c["default"].bind(h.__input,"change",l),c["default"].bind(h.__input,"blur",u),c["default"].bind(h.__input,"mousedown",p),c["default"].bind(h.__input,"keydown",function(e){13===e.keyCode&&(m.__truncationSuspended=!0,this.blur(),m.__truncationSuspended=!1,s())}),h.updateDisplay(),h.domElement.appendChild(h.__input),h}return a(t,e),t.prototype.updateDisplay=function(){return this.__input.value=this.__truncationSuspended?this.getValue():l(this.getValue(),this.__precision),e.prototype.updateDisplay.call(this)},t}(u["default"]);t["default"]=p},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t,n,o,i){return o+(i-o)*((e-t)/(n-t))}t.__esModule=!0;var s=n(12),u=o(s),d=n(9),c=o(d),f=function(e){function t(n,o,a,s,u){function d(e){document.activeElement.blur(),c["default"].bind(window,"mousemove",f),c["default"].bind(window,"mouseup",_),f(e)}function f(e){e.preventDefault();var t=h.__background.getBoundingClientRect();return h.setValue(l(e.clientX,t.left,t.right,h.__min,h.__max)),!1}function _(){c["default"].unbind(window,"mousemove",f),c["default"].unbind(window,"mouseup",_),h.__onFinishChange&&h.__onFinishChange.call(h,h.getValue())}i(this,t);var p=r(this,e.call(this,n,o,{min:a,max:s,step:u})),h=p;return p.__background=document.createElement("div"),p.__foreground=document.createElement("div"),c["default"].bind(p.__background,"mousedown",d),c["default"].addClass(p.__background,"slider"),c["default"].addClass(p.__foreground,"slider-fg"),p.updateDisplay(),p.__background.appendChild(p.__foreground),p.domElement.appendChild(p.__background),p}return a(t,e),t.prototype.updateDisplay=function(){var t=(this.getValue()-this.__min)/(this.__max-this.__min);return this.__foreground.style.width=100*t+"%",e.prototype.updateDisplay.call(this)},t}(u["default"]);t["default"]=f},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0;var l=n(7),s=o(l),u=n(9),d=o(u),c=function(e){function t(n,o,a){i(this,t);var l=r(this,e.call(this,n,o)),s=l;return l.__button=document.createElement("div"),l.__button.innerHTML=void 0===a?"Fire":a,d["default"].bind(l.__button,"click",function(e){return e.preventDefault(),s.fire(),!1}),d["default"].addClass(l.__button,"button"),l.domElement.appendChild(l.__button),l}return a(t,e),t.prototype.fire=function(){this.__onChange&&this.__onChange.call(this),this.getValue().call(this.object),this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())},t}(s["default"]);t["default"]=c},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t,n,o){e.style.background="",g["default"].each(y,function(i){e.style.cssText+="background: "+i+"linear-gradient("+t+", "+n+" 0%, "+o+" 100%); "})}function s(e){e.style.background="",e.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);",e.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}t.__esModule=!0;var u=n(7),d=o(u),c=n(9),f=o(c),_=n(2),p=o(_),h=n(3),m=o(h),b=n(5),g=o(b),v=function(e){function t(n,o){function a(e){h(e),f["default"].bind(window,"mousemove",h),f["default"].bind(window,"mouseup",u)}function u(){f["default"].unbind(window,"mousemove",h),f["default"].unbind(window,"mouseup",u),_()}function d(){var e=(0,m["default"])(this.value);e!==!1?(y.__color.__state=e,y.setValue(y.__color.toOriginal())):this.value=y.__color.toString()}function c(){f["default"].unbind(window,"mousemove",b),f["default"].unbind(window,"mouseup",c),_()}function _(){y.__onFinishChange&&y.__onFinishChange.call(y,y.__color.toOriginal())}function h(e){e.preventDefault();var t=y.__saturation_field.getBoundingClientRect(),n=(e.clientX-t.left)/(t.right-t.left),o=1-(e.clientY-t.top)/(t.bottom-t.top);return o>1?o=1:o<0&&(o=0),n>1?n=1:n<0&&(n=0),y.__color.v=o,y.__color.s=n,y.setValue(y.__color.toOriginal()),!1}function b(e){e.preventDefault();var t=y.__hue_field.getBoundingClientRect(),n=1-(e.clientY-t.top)/(t.bottom-t.top);return n>1?n=1:n<0&&(n=0),y.__color.h=360*n,y.setValue(y.__color.toOriginal()),!1}i(this,t);var v=r(this,e.call(this,n,o));v.__color=new p["default"](v.getValue()),v.__temp=new p["default"](0);var y=v;v.domElement=document.createElement("div"),f["default"].makeSelectable(v.domElement,!1),v.__selector=document.createElement("div"),v.__selector.className="selector",v.__saturation_field=document.createElement("div"),v.__saturation_field.className="saturation-field",v.__field_knob=document.createElement("div"),v.__field_knob.className="field-knob",v.__field_knob_border="2px solid ",v.__hue_knob=document.createElement("div"),v.__hue_knob.className="hue-knob",v.__hue_field=document.createElement("div"),v.__hue_field.className="hue-field",v.__input=document.createElement("input"),v.__input.type="text",v.__input_textShadow="0 1px 1px ",f["default"].bind(v.__input,"keydown",function(e){13===e.keyCode&&d.call(this)}),f["default"].bind(v.__input,"blur",d),f["default"].bind(v.__selector,"mousedown",function(){f["default"].addClass(this,"drag").bind(window,"mouseup",function(){f["default"].removeClass(y.__selector,"drag")})});var w=document.createElement("div");return g["default"].extend(v.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}),g["default"].extend(v.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:v.__field_knob_border+(v.__color.v<.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}),g["default"].extend(v.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}),g["default"].extend(v.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}),g["default"].extend(w.style,{width:"100%",height:"100%",background:"none"}),l(w,"top","rgba(0,0,0,0)","#000"),g["default"].extend(v.__hue_field.style,{width:"15px",height:"100px",border:"1px solid #555",cursor:"ns-resize",position:"absolute",top:"3px",right:"3px"}),s(v.__hue_field),g["default"].extend(v.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:v.__input_textShadow+"rgba(0,0,0,0.7)"}),f["default"].bind(v.__saturation_field,"mousedown",a),f["default"].bind(v.__field_knob,"mousedown",a),f["default"].bind(v.__hue_field,"mousedown",function(e){b(e),f["default"].bind(window,"mousemove",b),f["default"].bind(window,"mouseup",c)}),v.__saturation_field.appendChild(w),v.__selector.appendChild(v.__field_knob),v.__selector.appendChild(v.__saturation_field),v.__selector.appendChild(v.__hue_field),v.__hue_field.appendChild(v.__hue_knob),v.domElement.appendChild(v.__input),v.domElement.appendChild(v.__selector),v.updateDisplay(),v}return a(t,e),t.prototype.updateDisplay=function(){var e=(0,m["default"])(this.getValue());if(e!==!1){var t=!1;g["default"].each(p["default"].COMPONENTS,function(n){if(!g["default"].isUndefined(e[n])&&!g["default"].isUndefined(this.__color.__state[n])&&e[n]!==this.__color.__state[n])return t=!0,{}},this),t&&g["default"].extend(this.__color.__state,e)}g["default"].extend(this.__temp.__state,this.__color.__state),this.__temp.a=1;var n=this.__color.v<.5||this.__color.s>.5?255:0,o=255-n;g["default"].extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toHexString(),border:this.__field_knob_border+"rgb("+n+","+n+","+n+")"}),this.__hue_knob.style.marginTop=100*(1-this.__color.h/360)+"px",this.__temp.s=1,this.__temp.v=1,l(this.__saturation_field,"left","#fff",this.__temp.toHexString()),this.__input.value=this.__color.toString(),g["default"].extend(this.__input.style,{backgroundColor:this.__color.toHexString(),color:"rgb("+n+","+n+","+n+")",textShadow:this.__input_textShadow+"rgba("+o+","+o+","+o+",.7)"})},t}(d["default"]),y=["-moz-","-o-","-webkit-","-ms-",""];t["default"]=v},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t,n){var o=document.createElement("li");return t&&o.appendChild(t),n?e.__ul.insertBefore(o,n):e.__ul.appendChild(o),e.onResize(),o}function r(e,t){var n=e.__preset_select[e.__preset_select.selectedIndex];t?n.innerHTML=n.value+"*":n.innerHTML=n.value}function a(e,t,n){if(n.__li=t,n.__gui=e,U["default"].extend(n,{options:function(t){if(arguments.length>1){var o=n.__li.nextElementSibling;return n.remove(),s(e,n.object,n.property,{before:o,factoryArgs:[U["default"].toArray(arguments)]})}if(U["default"].isArray(t)||U["default"].isObject(t)){var i=n.__li.nextElementSibling;return n.remove(),s(e,n.object,n.property,{before:i,factoryArgs:[t]})}},name:function(e){return n.__li.firstElementChild.firstElementChild.innerHTML=e,n},listen:function(){return n.__gui.listen(n),n},remove:function(){ 14 | return n.__gui.remove(n),n}}),n instanceof B["default"])!function(){var e=new N["default"](n.object,n.property,{min:n.__min,max:n.__max,step:n.__step});U["default"].each(["updateDisplay","onChange","onFinishChange","step"],function(t){var o=n[t],i=e[t];n[t]=e[t]=function(){var t=Array.prototype.slice.call(arguments);return i.apply(e,t),o.apply(n,t)}}),z["default"].addClass(t,"has-slider"),n.domElement.insertBefore(e.domElement,n.domElement.firstElementChild)}();else if(n instanceof N["default"]){var o=function(t){if(U["default"].isNumber(n.__min)&&U["default"].isNumber(n.__max)){var o=n.__li.firstElementChild.firstElementChild.innerHTML,i=n.__gui.__listening.indexOf(n)>-1;n.remove();var r=s(e,n.object,n.property,{before:n.__li.nextElementSibling,factoryArgs:[n.__min,n.__max,n.__step]});return r.name(o),i&&r.listen(),r}return t};n.min=U["default"].compose(o,n.min),n.max=U["default"].compose(o,n.max)}else n instanceof O["default"]?(z["default"].bind(t,"click",function(){z["default"].fakeEvent(n.__checkbox,"click")}),z["default"].bind(n.__checkbox,"click",function(e){e.stopPropagation()})):n instanceof R["default"]?(z["default"].bind(t,"click",function(){z["default"].fakeEvent(n.__button,"click")}),z["default"].bind(t,"mouseover",function(){z["default"].addClass(n.__button,"hover")}),z["default"].bind(t,"mouseout",function(){z["default"].removeClass(n.__button,"hover")})):n instanceof j["default"]&&(z["default"].addClass(t,"color"),n.updateDisplay=U["default"].compose(function(e){return t.style.borderLeftColor=n.__color.toString(),e},n.updateDisplay),n.updateDisplay());n.setValue=U["default"].compose(function(t){return e.getRoot().__preset_select&&n.isModified()&&r(e.getRoot(),!0),t},n.setValue)}function l(e,t){var n=e.getRoot(),o=n.__rememberedObjects.indexOf(t.object);if(o!==-1){var i=n.__rememberedObjectIndecesToControllers[o];if(void 0===i&&(i={},n.__rememberedObjectIndecesToControllers[o]=i),i[t.property]=t,n.load&&n.load.remembered){var r=n.load.remembered,a=void 0;if(r[e.preset])a=r[e.preset];else{if(!r[Q])return;a=r[Q]}if(a[o]&&void 0!==a[o][t.property]){var l=a[o][t.property];t.initialValue=l,t.setValue(l)}}}}function s(e,t,n,o){if(void 0===t[n])throw new Error('Object "'+t+'" has no property "'+n+'"');var r=void 0;if(o.color)r=new j["default"](t,n);else{var s=[t,n].concat(o.factoryArgs);r=C["default"].apply(e,s)}o.before instanceof S["default"]&&(o.before=o.before.__li),l(e,r),z["default"].addClass(r.domElement,"c");var u=document.createElement("span");z["default"].addClass(u,"property-name"),u.innerHTML=r.property;var d=document.createElement("div");d.appendChild(u),d.appendChild(r.domElement);var c=i(e,d,o.before);return z["default"].addClass(c,oe.CLASS_CONTROLLER_ROW),r instanceof j["default"]?z["default"].addClass(c,"color"):z["default"].addClass(c,g(r.getValue())),a(e,c,r),e.__controllers.push(r),r}function u(e,t){return document.location.href+"."+t}function d(e,t,n){var o=document.createElement("option");o.innerHTML=t,o.value=t,e.__preset_select.appendChild(o),n&&(e.__preset_select.selectedIndex=e.__preset_select.length-1)}function c(e,t){t.style.display=e.useLocalStorage?"block":"none"}function f(e){var t=e.__save_row=document.createElement("li");z["default"].addClass(e.domElement,"has-save"),e.__ul.insertBefore(t,e.__ul.firstChild),z["default"].addClass(t,"save-row");var n=document.createElement("span");n.innerHTML=" ",z["default"].addClass(n,"button gears");var o=document.createElement("span");o.innerHTML="Save",z["default"].addClass(o,"button"),z["default"].addClass(o,"save");var i=document.createElement("span");i.innerHTML="New",z["default"].addClass(i,"button"),z["default"].addClass(i,"save-as");var r=document.createElement("span");r.innerHTML="Revert",z["default"].addClass(r,"button"),z["default"].addClass(r,"revert");var a=e.__preset_select=document.createElement("select");e.load&&e.load.remembered?U["default"].each(e.load.remembered,function(t,n){d(e,n,n===e.preset)}):d(e,Q,!1),z["default"].bind(a,"change",function(){for(var t=0;t0&&(e.preset=this.preset,e.remembered||(e.remembered={}),e.remembered[this.preset]=h(this)),e.folders={},U["default"].each(this.__folders,function(t,n){e.folders[n]=t.getSaveObject()}),e},save:function(){this.load.remembered||(this.load.remembered={}),this.load.remembered[this.preset]=h(this),r(this,!1),this.saveToLocalStorageIfPossible()},saveAs:function(e){this.load.remembered||(this.load.remembered={},this.load.remembered[Q]=h(this,!0)),this.load.remembered[e]=h(this),this.preset=e,d(this,e,!0),this.saveToLocalStorageIfPossible()},revert:function(e){U["default"].each(this.__controllers,function(t){this.getRoot().load.remembered?l(e||this.getRoot(),t):t.setValue(t.initialValue),t.__onFinishChange&&t.__onFinishChange.call(t,t.getValue())},this),U["default"].each(this.__folders,function(e){e.revert(e)}),e||r(this.getRoot(),!1)},listen:function(e){var t=0===this.__listening.length;this.__listening.push(e),t&&b(this.__listening)},updateDisplay:function(){U["default"].each(this.__controllers,function(e){e.updateDisplay()}),U["default"].each(this.__folders,function(e){e.updateDisplay()})}}),e.exports=oe},function(e,t){"use strict";e.exports={load:function(e,t){var n=t||document,o=n.createElement("link");o.type="text/css",o.rel="stylesheet",o.href=e,n.getElementsByTagName("head")[0].appendChild(o)},inject:function(e,t){var n=t||document,o=document.createElement("style");o.type="text/css",o.innerHTML=e;var i=n.getElementsByTagName("head")[0];try{i.appendChild(o)}catch(r){}}}},function(e,t){e.exports="
Here's the new load parameter for your GUI's constructor:
Automatically save values to localStorage on exit.
The values saved to localStorage will override those passed to dat.GUI's constructor. This makes it easier to work incrementally, but localStorage is fragile, and your friends may not see the same values you do.
"},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0;var i=n(10),r=o(i),a=n(13),l=o(a),s=n(14),u=o(s),d=n(11),c=o(d),f=n(15),_=o(f),p=n(8),h=o(p),m=n(5),b=o(m),g=function(e,t){var n=e[t];return b["default"].isArray(arguments[2])||b["default"].isObject(arguments[2])?new r["default"](e,t,arguments[2]):b["default"].isNumber(n)?b["default"].isNumber(arguments[2])&&b["default"].isNumber(arguments[3])?b["default"].isNumber(arguments[4])?new u["default"](e,t,arguments[2],arguments[3],arguments[4]):new u["default"](e,t,arguments[2],arguments[3]):b["default"].isNumber(arguments[4])?new l["default"](e,t,{min:arguments[2],max:arguments[3],step:arguments[4]}):new l["default"](e,t,{min:arguments[2],max:arguments[3]}):b["default"].isString(n)?new c["default"](e,t):b["default"].isFunction(n)?new _["default"](e,t,""):b["default"].isBoolean(n)?new h["default"](e,t):null};t["default"]=g},function(e,t){"use strict";function n(e){setTimeout(e,1e3/60)}t.__esModule=!0,t["default"]=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||n},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var r=n(9),a=o(r),l=n(5),s=o(l),u=function(){function e(){i(this,e),this.backgroundElement=document.createElement("div"),s["default"].extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear",transition:"opacity 0.2s linear"}),a["default"].makeFullscreen(this.backgroundElement),this.backgroundElement.style.position="fixed",this.domElement=document.createElement("div"),s["default"].extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear",transition:"transform 0.2s ease-out, opacity 0.2s linear"}),document.body.appendChild(this.backgroundElement),document.body.appendChild(this.domElement);var t=this;a["default"].bind(this.backgroundElement,"click",function(){t.hide()})}return e.prototype.show=function(){var e=this;this.backgroundElement.style.display="block",this.domElement.style.display="block",this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)",this.layout(),s["default"].defer(function(){e.backgroundElement.style.opacity=1,e.domElement.style.opacity=1,e.domElement.style.webkitTransform="scale(1)"})},e.prototype.hide=function t(){var e=this,t=function n(){e.domElement.style.display="none",e.backgroundElement.style.display="none",a["default"].unbind(e.domElement,"webkitTransitionEnd",n),a["default"].unbind(e.domElement,"transitionend",n),a["default"].unbind(e.domElement,"oTransitionEnd",n)};a["default"].bind(this.domElement,"webkitTransitionEnd",t),a["default"].bind(this.domElement,"transitionend",t),a["default"].bind(this.domElement,"oTransitionEnd",t),this.backgroundElement.style.opacity=0,this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)"},e.prototype.layout=function(){this.domElement.style.left=window.innerWidth/2-a["default"].getWidth(this.domElement)/2+"px",this.domElement.style.top=window.innerHeight/2-a["default"].getHeight(this.domElement)/2+"px"},e}();t["default"]=u},function(e,t,n){t=e.exports=n(24)(),t.push([e.id,".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1!important}.dg.main .close-button.drag,.dg.main:hover .close-button{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;transition:opacity .1s linear;border:0;position:absolute;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-x:hidden}.dg.a.has-save>ul{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{position:fixed;top:0;z-index:1002}.dg li{-webkit-transition:height .1s ease-out;transition:height .1s ease-out}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;overflow:hidden;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid transparent}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:9px}.dg .c select{margin-top:5px}.dg .cr.boolean,.dg .cr.boolean *,.dg .cr.function,.dg .cr.function *,.dg .cr.function .property-name{cursor:pointer}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco,monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px Lucida Grande,sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid hsla(0,0%,100%,.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2fa1d6}.dg .cr.number input[type=text]{color:#2fa1d6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.boolean:hover,.dg .cr.function:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2fa1d6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}",""])},function(e,t){e.exports=function(){var e=[];return e.toString=function(){for(var e=[],t=0;t 5 | 6 | (c) 2014 Stuart Knightley, David Duponchel 7 | Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown. 8 | 9 | */ 10 | !function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.JSZipUtils=e():"undefined"!=typeof global?global.JSZipUtils=e():"undefined"!=typeof self&&(self.JSZipUtils=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0 ? blocks[0].w : 0; 67 | var h = len > 0 ? blocks[0].h : 0; 68 | this.root = { x: 0, y: 0, w: w, h: h }; 69 | for (n = 0; n < len ; n++) { 70 | block = blocks[n]; 71 | if (node = this.findNode(this.root, block.w, block.h)) 72 | block.fit = this.splitNode(node, block.w, block.h); 73 | else 74 | block.fit = this.growNode(block.w, block.h); 75 | } 76 | }, 77 | 78 | findNode: function(root, w, h) { 79 | if (root.used) 80 | return this.findNode(root.right, w, h) || this.findNode(root.down, w, h); 81 | else if ((w <= root.w) && (h <= root.h)) 82 | return root; 83 | else 84 | return null; 85 | }, 86 | 87 | splitNode: function(node, w, h) { 88 | node.used = true; 89 | node.down = { x: node.x, y: node.y + h, w: node.w, h: node.h - h }; 90 | node.right = { x: node.x + w, y: node.y, w: node.w - w, h: h }; 91 | return node; 92 | }, 93 | 94 | growNode: function(w, h) { 95 | var canGrowDown = (w <= this.root.w); 96 | var canGrowRight = (h <= this.root.h); 97 | 98 | var shouldGrowRight = canGrowRight && (this.root.h >= (this.root.w + w)); // attempt to keep square-ish by growing right when height is much greater than width 99 | var shouldGrowDown = canGrowDown && (this.root.w >= (this.root.h + h)); // attempt to keep square-ish by growing down when width is much greater than height 100 | 101 | if (shouldGrowRight) 102 | return this.growRight(w, h); 103 | else if (shouldGrowDown) 104 | return this.growDown(w, h); 105 | else if (canGrowRight) 106 | return this.growRight(w, h); 107 | else if (canGrowDown) 108 | return this.growDown(w, h); 109 | else 110 | return null; // need to ensure sensible root starting size to avoid this happening 111 | }, 112 | 113 | growRight: function(w, h) { 114 | this.root = { 115 | used: true, 116 | x: 0, 117 | y: 0, 118 | w: this.root.w + w, 119 | h: this.root.h, 120 | down: this.root, 121 | right: { x: this.root.w, y: 0, w: w, h: this.root.h } 122 | }; 123 | if (node = this.findNode(this.root, w, h)) 124 | return this.splitNode(node, w, h); 125 | else 126 | return null; 127 | }, 128 | 129 | growDown: function(w, h) { 130 | this.root = { 131 | used: true, 132 | x: 0, 133 | y: 0, 134 | w: this.root.w, 135 | h: this.root.h + h, 136 | down: { x: 0, y: this.root.h, w: this.root.w, h: h }, 137 | right: this.root 138 | }; 139 | if (node = this.findNode(this.root, w, h)) 140 | return this.splitNode(node, w, h); 141 | else 142 | return null; 143 | } 144 | 145 | } 146 | 147 | 148 | -------------------------------------------------------------------------------- /obj/sponza_01/00_skap.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/00_skap.JPG -------------------------------------------------------------------------------- /obj/sponza_01/01_STUB-bump.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/01_STUB-bump.jpg -------------------------------------------------------------------------------- /obj/sponza_01/01_STUB.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/01_STUB.JPG -------------------------------------------------------------------------------- /obj/sponza_01/01_S_ba.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/01_S_ba.JPG -------------------------------------------------------------------------------- /obj/sponza_01/01_S_kap-bump.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/01_S_kap-bump.jpg -------------------------------------------------------------------------------- /obj/sponza_01/01_S_kap.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/01_S_kap.JPG -------------------------------------------------------------------------------- /obj/sponza_01/01_St_kp-bump.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/01_St_kp-bump.jpg -------------------------------------------------------------------------------- /obj/sponza_01/01_St_kp.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/01_St_kp.JPG -------------------------------------------------------------------------------- /obj/sponza_01/KAMEN-bump.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/KAMEN-bump.jpg -------------------------------------------------------------------------------- /obj/sponza_01/KAMEN-stup.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/KAMEN-stup.JPG -------------------------------------------------------------------------------- /obj/sponza_01/KAMEN.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/KAMEN.JPG -------------------------------------------------------------------------------- /obj/sponza_01/copyright.txt: -------------------------------------------------------------------------------- 1 | http://hdri.cgtechniques.com/~sponza/files/ 2 | 3 | Sponza modeled by Marko Dabrovic, with UVs and crack errors fixed by Kenzie Lamar at Vicarious Visions. 4 | Bump maps painted by Morgan McGuire. 5 | -------------------------------------------------------------------------------- /obj/sponza_01/prozor1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/prozor1.JPG -------------------------------------------------------------------------------- /obj/sponza_01/reljef-bump.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/reljef-bump.jpg -------------------------------------------------------------------------------- /obj/sponza_01/reljef.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/reljef.JPG -------------------------------------------------------------------------------- /obj/sponza_01/sp_luk-bump.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/sp_luk-bump.JPG -------------------------------------------------------------------------------- /obj/sponza_01/sp_luk.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/sp_luk.JPG -------------------------------------------------------------------------------- /obj/sponza_01/sponza.mtl: -------------------------------------------------------------------------------- 1 | # 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware 2 | # File Created: 26.07.2011 17:00:30 3 | 4 | newmtl sp_00_luk_mali 5 | Ns 50.000000 6 | Ni 1.500000 7 | d 1.000000 8 | Tr 0.000000 9 | Tf 1.000000 1.000000 1.000000 10 | illum 2 11 | Ka 0.000000 0.000000 0.000000 12 | Kd 0.745098 0.709804 0.674510 13 | Ks 0.000000 0.000000 0.000000 14 | Ke 0.000000 0.000000 0.000000 15 | map_Ka SP_LUK.JPG 16 | map_Kd SP_LUK.JPG 17 | map_bump sp_luk-bump.JPG 18 | bump sp_luk-bump.JPG 19 | 20 | newmtl sp_svod_kapitel 21 | Ns 50.000000 22 | Ni 1.500000 23 | d 1.000000 24 | Tr 0.000000 25 | Tf 1.000000 1.000000 1.000000 26 | illum 2 27 | Ka 0.000000 0.000000 0.000000 28 | Kd 0.713726 0.705882 0.658824 29 | Ks 0.000000 0.000000 0.000000 30 | Ke 0.000000 0.000000 0.000000 31 | map_Ka 00_SKAP.JPG 32 | map_Kd 00_SKAP.JPG 33 | map_bump 00_SKAP.JPG 34 | bump 00_SKAP.JPG 35 | 36 | newmtl sp_01_stub_baza_ 37 | Ns 19.999998 38 | Ni 1.500000 39 | d 1.000000 40 | Tr 0.000000 41 | Tf 1.000000 1.000000 1.000000 42 | illum 2 43 | Ka 0.000000 0.000000 0.000000 44 | Kd 0.784314 0.784314 0.784314 45 | Ks 0.000000 0.000000 0.000000 46 | Ke 0.000000 0.000000 0.000000 47 | 48 | newmtl sp_01_stub_kut 49 | Ns 50.000000 50 | Ni 1.500000 51 | d 1.000000 52 | Tr 0.000000 53 | Tf 1.000000 1.000000 1.000000 54 | illum 2 55 | Ka 0.000000 0.000000 0.000000 56 | Kd 0.737255 0.709804 0.670588 57 | Ks 0.000000 0.000000 0.000000 58 | Ke 0.000000 0.000000 0.000000 59 | map_Ka 01_STUB.JPG 60 | map_Kd 01_STUB.JPG 61 | map_bump 01_STUB-bump.jpg 62 | bump 01_STUB-bump.jpg 63 | 64 | newmtl sp_00_stup 65 | Ns 50.000000 66 | Ni 1.500000 67 | d 1.000000 68 | Tr 0.000000 69 | Tf 1.000000 1.000000 1.000000 70 | illum 2 71 | Ka 0.000000 0.000000 0.000000 72 | Kd 0.737255 0.709804 0.670588 73 | Ks 0.000000 0.000000 0.000000 74 | Ke 0.000000 0.000000 0.000000 75 | map_Ka 01_STUB.JPG 76 | map_Kd 01_STUB.JPG 77 | map_bump 01_STUB-bump.jpg 78 | bump 01_STUB-bump.jpg 79 | 80 | newmtl sp_01_stub_baza 81 | Ns 50.000000 82 | Ni 1.500000 83 | d 1.000000 84 | Tr 0.000000 85 | Tf 1.000000 1.000000 1.000000 86 | illum 2 87 | Ka 0.000000 0.000000 0.000000 88 | Kd 0.800000 0.784314 0.749020 89 | Ks 0.000000 0.000000 0.000000 90 | Ke 0.000000 0.000000 0.000000 91 | map_Ka 01_S_BA.JPG 92 | map_Kd 01_S_BA.JPG 93 | map_bump 01_S_BA.JPG 94 | bump 01_S_BA.JPG 95 | 96 | newmtl sp_00_luk_mal1 97 | Ns 50.000000 98 | Ni 1.500000 99 | d 1.000000 100 | Tr 0.000000 101 | Tf 1.000000 1.000000 1.000000 102 | illum 2 103 | Ka 0.000000 0.000000 0.000000 104 | Kd 0.745098 0.709804 0.674510 105 | Ks 0.000000 0.000000 0.000000 106 | Ke 0.000000 0.000000 0.000000 107 | map_Ka 01_ST_KP.JPG 108 | map_Kd 01_ST_KP.JPG 109 | map_bump 01_St_kp-bump.jpg 110 | bump 01_St_kp-bump.jpg 111 | 112 | newmtl sp_01_stub 113 | Ns 50.000000 114 | Ni 1.500000 115 | d 1.000000 116 | Tr 0.000000 117 | Tf 1.000000 1.000000 1.000000 118 | illum 2 119 | Ka 0.000000 0.000000 0.000000 120 | Kd 0.737255 0.709804 0.670588 121 | Ks 0.000000 0.000000 0.000000 122 | Ke 0.000000 0.000000 0.000000 123 | map_Ka 01_STUB.JPG 124 | map_Kd 01_STUB.JPG 125 | map_bump 01_STUB-bump.jpg 126 | bump 01_STUB-bump.jpg 127 | 128 | newmtl sp_01_stup 129 | Ns 50.000000 130 | Ni 1.500000 131 | d 1.000000 132 | Tr 0.000000 133 | Tf 1.000000 1.000000 1.000000 134 | illum 2 135 | Ka 0.000000 0.000000 0.000000 136 | Kd 0.827451 0.800000 0.768628 137 | Ks 0.000000 0.000000 0.000000 138 | Ke 0.000000 0.000000 0.000000 139 | map_Ka X01_ST.JPG 140 | map_Kd X01_ST.JPG 141 | 142 | newmtl sp_vijenac 143 | Ns 50.000000 144 | Ni 1.500000 145 | d 1.000000 146 | Tr 0.000000 147 | Tf 1.000000 1.000000 1.000000 148 | illum 2 149 | Ka 0.000000 0.000000 0.000000 150 | Kd 0.713726 0.705882 0.658824 151 | Ks 0.000000 0.000000 0.000000 152 | Ke 0.000000 0.000000 0.000000 153 | map_Ka 00_SKAP.JPG 154 | map_Kd 00_SKAP.JPG 155 | map_bump 00_SKAP.JPG 156 | bump 00_SKAP.JPG 157 | 158 | newmtl sp_00_svod 159 | Ns 1.000000 160 | Ni 1.500000 161 | d 1.000000 162 | Tr 0.000000 163 | Tf 1.000000 1.000000 1.000000 164 | illum 2 165 | Ka 0.145098 0.145098 0.145098 166 | Kd 0.941177 0.866667 0.737255 167 | Ks 0.034039 0.032314 0.029333 168 | Ke 0.000000 0.000000 0.000000 169 | map_Kd KAMEN-stup.JPG 170 | map_Ka KAMEN-stup.JPG 171 | map_bump KAMEN-stup.jpg 172 | bump KAMEN-stup.jpg 173 | 174 | newmtl sp_02_reljef 175 | Ns 50.000000 176 | Ni 1.500000 177 | d 1.000000 178 | Tr 0.000000 179 | Tf 1.000000 1.000000 1.000000 180 | illum 2 181 | Ka 0.000000 0.000000 0.000000 182 | Kd 0.529412 0.498039 0.490196 183 | Ks 0.000000 0.000000 0.000000 184 | Ke 0.000000 0.000000 0.000000 185 | map_Ka RELJEF.JPG 186 | map_Kd RELJEF.JPG 187 | map_bump reljef-bump.jpg 188 | bump reljef-bump.jpg 189 | 190 | newmtl sp_01_luk_a 191 | Ns 50.000000 192 | Ni 1.500000 193 | d 1.000000 194 | Tr 0.000000 195 | Tf 1.000000 1.000000 1.000000 196 | illum 2 197 | Ka 0.000000 0.000000 0.000000 198 | Kd 0.745098 0.709804 0.674510 199 | Ks 0.000000 0.000000 0.000000 200 | Ke 0.000000 0.000000 0.000000 201 | map_Ka SP_LUK.JPG 202 | map_Kd SP_LUK.JPG 203 | map_bump sp_luk-bump.JPG 204 | bump sp_luk-bump.JPG 205 | 206 | newmtl sp_zid_vani 207 | Ns 50.000000 208 | Ni 1.500000 209 | d 1.000000 210 | Tr 0.000000 211 | Tf 1.000000 1.000000 1.000000 212 | illum 2 213 | Ka 0.000000 0.000000 0.000000 214 | Kd 0.627451 0.572549 0.560784 215 | Ks 0.000000 0.000000 0.000000 216 | Ke 0.000000 0.000000 0.000000 217 | map_Ka KAMEN.JPG 218 | map_Kd KAMEN.JPG 219 | map_bump KAMEN-bump.jpg 220 | bump KAMEN-bump.jpg 221 | 222 | newmtl sp_01_stup_baza 223 | Ns 50.000000 224 | Ni 1.500000 225 | d 1.000000 226 | Tr 0.000000 227 | Tf 1.000000 1.000000 1.000000 228 | illum 2 229 | Ka 0.000000 0.000000 0.000000 230 | Kd 0.800000 0.784314 0.749020 231 | Ks 0.000000 0.000000 0.000000 232 | Ke 0.000000 0.000000 0.000000 233 | map_Ka 01_S_BA.JPG 234 | map_Kd 01_S_BA.JPG 235 | map_bump 01_S_BA.JPG 236 | bump 01_S_BA.JPG 237 | 238 | newmtl sp_00_zid 239 | Ns 50.000000 240 | Ni 1.500000 241 | d 1.000000 242 | Tr 0.000000 243 | Tf 1.000000 1.000000 1.000000 244 | illum 2 245 | Ka 0.000000 0.000000 0.000000 246 | Kd 0.627451 0.572549 0.560784 247 | Ks 0.000000 0.000000 0.000000 248 | Ke 0.000000 0.000000 0.000000 249 | map_Ka KAMEN.JPG 250 | map_Kd KAMEN.JPG 251 | map_bump KAMEN-bump.jpg 252 | bump KAMEN-bump.jpg 253 | 254 | newmtl sp_00_prozor 255 | Ns 50.000000 256 | Ni 1.500000 257 | d 1.000000 258 | Tr 0.000000 259 | Tf 1.000000 1.000000 1.000000 260 | illum 2 261 | Ka 0.000000 0.000000 0.000000 262 | Kd 1.000000 1.000000 1.000000 263 | Ks 0.000000 0.000000 0.000000 264 | Ke 0.000000 0.000000 0.000000 265 | map_Ka PROZOR1.JPG 266 | map_Kd PROZOR1.JPG 267 | map_bump PROZOR1.JPG 268 | bump PROZOR1.JPG 269 | 270 | newmtl sp_00_vrata_krug 271 | Ns 19.999998 272 | Ni 1.500000 273 | d 1.000000 274 | Tr 0.000000 275 | Tf 1.000000 1.000000 1.000000 276 | illum 2 277 | Ka 0.000000 0.000000 0.000000 278 | Kd 0.784314 0.784314 0.784314 279 | Ks 0.000000 0.000000 0.000000 280 | Ke 0.000000 0.000000 0.000000 281 | map_Ka VRATA_KR.JPG 282 | map_Kd VRATA_KR.JPG 283 | map_bump VRATA_KR.JPG 284 | bump VRATA_KR.JPG 285 | 286 | newmtl sp_00_pod 287 | Ns 50.000000 288 | Ni 1.500000 289 | d 1.000000 290 | Tr 0.000000 291 | Tf 1.000000 1.000000 1.000000 292 | illum 2 293 | Ka 0.000000 0.000000 0.000000 294 | Kd 0.627451 0.572549 0.560784 295 | Ks 0.000000 0.000000 0.000000 296 | Ke 0.000000 0.000000 0.000000 297 | map_Ka KAMEN.JPG 298 | map_Kd KAMEN.JPG 299 | map_bump KAMEN-bump.jpg 300 | bump KAMEN-bump.jpg 301 | 302 | newmtl sp_00_vrata_kock 303 | Ns 19.999998 304 | Ni 1.500000 305 | d 1.000000 306 | Tr 0.000000 307 | Tf 1.000000 1.000000 1.000000 308 | illum 2 309 | Ka 0.000000 0.000000 0.000000 310 | Kd 0.784314 0.784314 0.784314 311 | Ks 0.000000 0.000000 0.000000 312 | Ke 0.000000 0.000000 0.000000 313 | map_Ka VRATA_KO.JPG 314 | map_Kd VRATA_KO.JPG 315 | map_bump VRATA_KO.JPG 316 | bump VRATA_KO.JPG 317 | -------------------------------------------------------------------------------- /obj/sponza_01/vrata_ko.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/vrata_ko.JPG -------------------------------------------------------------------------------- /obj/sponza_01/vrata_kr.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/vrata_kr.JPG -------------------------------------------------------------------------------- /obj/sponza_01/x01_st-bump.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/x01_st-bump.jpg -------------------------------------------------------------------------------- /obj/sponza_01/x01_st.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manthrax/lightbaking/ee90b62e7215183477a76ceb2e81dc4ab4b95414/obj/sponza_01/x01_st.JPG --------------------------------------------------------------------------------