├── screenshot.jpg ├── docs ├── assets │ ├── images │ │ └── logo.png │ ├── dependencies │ │ ├── gl-matrix-LICENSE │ │ ├── dat.gui.css │ │ ├── dat.gui-LICENSE │ │ └── dat.gui.min.js │ ├── css │ │ └── index.css │ └── scripts │ │ └── index.js └── index.html ├── source ├── assets │ ├── images │ │ └── logo.png │ ├── css │ │ └── index.css │ └── scripts │ │ └── index.js └── index.html └── README.md /screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lettier/isosurface/HEAD/screenshot.jpg -------------------------------------------------------------------------------- /docs/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lettier/isosurface/HEAD/docs/assets/images/logo.png -------------------------------------------------------------------------------- /source/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lettier/isosurface/HEAD/source/assets/images/logo.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Isosurface](https://i.imgur.com/KjOGPoi.gif) 2 | 3 | # Isosurface Extraction 4 | 5 | Isosurface extraction using the Marching Cubes algorithm. Uses only pure WebGL. 6 | 7 | Requires [glMatrix](https://github.com/toji/gl-matrix) and [dat.gui](https://github.com/dataarts/dat.gui). 8 | 9 | (C) 2014 David Lettier 10 | [lettier.com](http://www.lettier.com) 11 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Isosurface | Lettier 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /source/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Isosurface | Lettier 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/assets/dependencies/gl-matrix-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /docs/assets/css/index.css: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2013 David Lettier 3 | lettier.com 4 | */ 5 | 6 | body 7 | { 8 | 9 | margin: 0px; 10 | padding: 0px; 11 | overflow: hidden; 12 | 13 | } 14 | 15 | .lighting_power_text_box 16 | { 17 | 18 | margin: 0px; 19 | padding: 5px; 20 | position: absolute; 21 | left: 50px; 22 | top: 75px; 23 | z-index: 3; 24 | font-family: sans-serif; 25 | font-size: 35px; 26 | cursor: default; 27 | color: #fff; 28 | -webkit-touch-callout: none; 29 | -webkit-user-select: none; 30 | -khtml-user-select: none; 31 | -moz-user-select: none; 32 | -ms-user-select: none; 33 | user-select: none; 34 | 35 | } 36 | 37 | .up_button 38 | { 39 | 40 | margin: 0px; 41 | padding: 5px; 42 | position: absolute; 43 | left: 10px; 44 | top: 8px; 45 | z-index: 3; 46 | font-family: sans-serif; 47 | font-size: 80px; 48 | cursor: pointer; 49 | color: #fff; 50 | -webkit-touch-callout: none; 51 | -webkit-user-select: none; 52 | -khtml-user-select: none; 53 | -moz-user-select: none; 54 | -ms-user-select: none; 55 | user-select: none; 56 | 57 | } 58 | 59 | .down_button 60 | { 61 | 62 | margin: 0px; 63 | padding: 5px; 64 | position: absolute; 65 | left: 10px; 66 | top: 80px; 67 | z-index: 3; 68 | font-family: sans-serif; 69 | font-size: 80px; 70 | cursor: pointer; 71 | color: #fff; 72 | -webkit-touch-callout: none; 73 | -webkit-user-select: none; 74 | -khtml-user-select: none; 75 | -moz-user-select: none; 76 | -ms-user-select: none; 77 | user-select: none; 78 | 79 | } 80 | 81 | .projection_text_box 82 | { 83 | 84 | margin: 0px; 85 | padding: 5px; 86 | position: absolute; 87 | left: 20px; 88 | top: 170px; 89 | z-index: 3; 90 | font-family: sans-serif; 91 | font-size: 35px; 92 | cursor: pointer; 93 | color: #fff; 94 | -webkit-touch-callout: none; 95 | -webkit-user-select: none; 96 | -khtml-user-select: none; 97 | -moz-user-select: none; 98 | -ms-user-select: none; 99 | user-select: none; 100 | 101 | } 102 | 103 | .use_wireframe_text_box 104 | { 105 | 106 | margin: 0px; 107 | padding: 5px; 108 | position: absolute; 109 | left: 20px; 110 | top: 220px; 111 | z-index: 3; 112 | font-family: sans-serif; 113 | font-size: 35px; 114 | cursor: pointer; 115 | color: #fff; 116 | -webkit-touch-callout: none; 117 | -webkit-user-select: none; 118 | -khtml-user-select: none; 119 | -moz-user-select: none; 120 | -ms-user-select: none; 121 | user-select: none; 122 | 123 | } 124 | 125 | .show_depth_text_box 126 | { 127 | 128 | margin: 0px; 129 | padding: 5px; 130 | position: absolute; 131 | left: 20px; 132 | top: 270px; 133 | z-index: 3; 134 | font-family: sans-serif; 135 | font-size: 35px; 136 | cursor: pointer; 137 | color: #fff; 138 | -webkit-touch-callout: none; 139 | -webkit-user-select: none; 140 | -khtml-user-select: none; 141 | -moz-user-select: none; 142 | -ms-user-select: none; 143 | user-select: none; 144 | 145 | } 146 | 147 | .show_normals_text_box 148 | { 149 | 150 | margin: 0px; 151 | padding: 5px; 152 | position: absolute; 153 | left: 20px; 154 | top: 320px; 155 | z-index: 3; 156 | font-family: sans-serif; 157 | font-size: 35px; 158 | cursor: pointer; 159 | color: #fff; 160 | -webkit-touch-callout: none; 161 | -webkit-user-select: none; 162 | -khtml-user-select: none; 163 | -moz-user-select: none; 164 | -ms-user-select: none; 165 | user-select: none; 166 | 167 | } 168 | 169 | .show_position_text_box 170 | { 171 | 172 | margin: 0px; 173 | padding: 5px; 174 | position: absolute; 175 | left: 20px; 176 | top: 370px; 177 | z-index: 3; 178 | font-family: sans-serif; 179 | font-size: 35px; 180 | cursor: pointer; 181 | color: #fff; 182 | -webkit-touch-callout: none; 183 | -webkit-user-select: none; 184 | -khtml-user-select: none; 185 | -moz-user-select: none; 186 | -ms-user-select: none; 187 | user-select: none; 188 | 189 | } 190 | 191 | .logo_box 192 | { 193 | 194 | margin: 0px; 195 | padding: 5px; 196 | position: absolute; 197 | left: 0px; 198 | top: 0px; 199 | z-index: 3; 200 | width: auto; 201 | height: auto; 202 | -webkit-touch-callout: none; 203 | -webkit-user-select: none; 204 | -khtml-user-select: none; 205 | -moz-user-select: none; 206 | -ms-user-select: none; 207 | user-select: none; 208 | 209 | } 210 | 211 | .logo 212 | { 213 | 214 | margin: 0px; 215 | border: 0px; 216 | width: 300px; 217 | height: 300px; 218 | opacity: 0.8; 219 | cursor: pointer; 220 | filter: alpha( opacity = 80 ); 221 | -webkit-touch-callout: none; 222 | -webkit-user-select: none; 223 | -khtml-user-select: none; 224 | -moz-user-select: none; 225 | -ms-user-select: none; 226 | user-select: none; 227 | 228 | } 229 | -------------------------------------------------------------------------------- /source/assets/css/index.css: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2013 David Lettier 3 | lettier.com 4 | */ 5 | 6 | body 7 | { 8 | 9 | margin: 0px; 10 | padding: 0px; 11 | overflow: hidden; 12 | 13 | } 14 | 15 | .lighting_power_text_box 16 | { 17 | 18 | margin: 0px; 19 | padding: 5px; 20 | position: absolute; 21 | left: 50px; 22 | top: 75px; 23 | z-index: 3; 24 | font-family: sans-serif; 25 | font-size: 35px; 26 | cursor: default; 27 | color: #fff; 28 | -webkit-touch-callout: none; 29 | -webkit-user-select: none; 30 | -khtml-user-select: none; 31 | -moz-user-select: none; 32 | -ms-user-select: none; 33 | user-select: none; 34 | 35 | } 36 | 37 | .up_button 38 | { 39 | 40 | margin: 0px; 41 | padding: 5px; 42 | position: absolute; 43 | left: 10px; 44 | top: 8px; 45 | z-index: 3; 46 | font-family: sans-serif; 47 | font-size: 80px; 48 | cursor: pointer; 49 | color: #fff; 50 | -webkit-touch-callout: none; 51 | -webkit-user-select: none; 52 | -khtml-user-select: none; 53 | -moz-user-select: none; 54 | -ms-user-select: none; 55 | user-select: none; 56 | 57 | } 58 | 59 | .down_button 60 | { 61 | 62 | margin: 0px; 63 | padding: 5px; 64 | position: absolute; 65 | left: 10px; 66 | top: 80px; 67 | z-index: 3; 68 | font-family: sans-serif; 69 | font-size: 80px; 70 | cursor: pointer; 71 | color: #fff; 72 | -webkit-touch-callout: none; 73 | -webkit-user-select: none; 74 | -khtml-user-select: none; 75 | -moz-user-select: none; 76 | -ms-user-select: none; 77 | user-select: none; 78 | 79 | } 80 | 81 | .projection_text_box 82 | { 83 | 84 | margin: 0px; 85 | padding: 5px; 86 | position: absolute; 87 | left: 20px; 88 | top: 170px; 89 | z-index: 3; 90 | font-family: sans-serif; 91 | font-size: 35px; 92 | cursor: pointer; 93 | color: #fff; 94 | -webkit-touch-callout: none; 95 | -webkit-user-select: none; 96 | -khtml-user-select: none; 97 | -moz-user-select: none; 98 | -ms-user-select: none; 99 | user-select: none; 100 | 101 | } 102 | 103 | .use_wireframe_text_box 104 | { 105 | 106 | margin: 0px; 107 | padding: 5px; 108 | position: absolute; 109 | left: 20px; 110 | top: 220px; 111 | z-index: 3; 112 | font-family: sans-serif; 113 | font-size: 35px; 114 | cursor: pointer; 115 | color: #fff; 116 | -webkit-touch-callout: none; 117 | -webkit-user-select: none; 118 | -khtml-user-select: none; 119 | -moz-user-select: none; 120 | -ms-user-select: none; 121 | user-select: none; 122 | 123 | } 124 | 125 | .show_depth_text_box 126 | { 127 | 128 | margin: 0px; 129 | padding: 5px; 130 | position: absolute; 131 | left: 20px; 132 | top: 270px; 133 | z-index: 3; 134 | font-family: sans-serif; 135 | font-size: 35px; 136 | cursor: pointer; 137 | color: #fff; 138 | -webkit-touch-callout: none; 139 | -webkit-user-select: none; 140 | -khtml-user-select: none; 141 | -moz-user-select: none; 142 | -ms-user-select: none; 143 | user-select: none; 144 | 145 | } 146 | 147 | .show_normals_text_box 148 | { 149 | 150 | margin: 0px; 151 | padding: 5px; 152 | position: absolute; 153 | left: 20px; 154 | top: 320px; 155 | z-index: 3; 156 | font-family: sans-serif; 157 | font-size: 35px; 158 | cursor: pointer; 159 | color: #fff; 160 | -webkit-touch-callout: none; 161 | -webkit-user-select: none; 162 | -khtml-user-select: none; 163 | -moz-user-select: none; 164 | -ms-user-select: none; 165 | user-select: none; 166 | 167 | } 168 | 169 | .show_position_text_box 170 | { 171 | 172 | margin: 0px; 173 | padding: 5px; 174 | position: absolute; 175 | left: 20px; 176 | top: 370px; 177 | z-index: 3; 178 | font-family: sans-serif; 179 | font-size: 35px; 180 | cursor: pointer; 181 | color: #fff; 182 | -webkit-touch-callout: none; 183 | -webkit-user-select: none; 184 | -khtml-user-select: none; 185 | -moz-user-select: none; 186 | -ms-user-select: none; 187 | user-select: none; 188 | 189 | } 190 | 191 | .logo_box 192 | { 193 | 194 | margin: 0px; 195 | padding: 5px; 196 | position: absolute; 197 | left: 0px; 198 | top: 0px; 199 | z-index: 3; 200 | width: auto; 201 | height: auto; 202 | -webkit-touch-callout: none; 203 | -webkit-user-select: none; 204 | -khtml-user-select: none; 205 | -moz-user-select: none; 206 | -ms-user-select: none; 207 | user-select: none; 208 | 209 | } 210 | 211 | .logo 212 | { 213 | 214 | margin: 0px; 215 | border: 0px; 216 | width: 300px; 217 | height: 300px; 218 | opacity: 0.8; 219 | cursor: pointer; 220 | filter: alpha( opacity = 80 ); 221 | -webkit-touch-callout: none; 222 | -webkit-user-select: none; 223 | -khtml-user-select: none; 224 | -moz-user-select: none; 225 | -ms-user-select: none; 226 | user-select: none; 227 | 228 | } 229 | -------------------------------------------------------------------------------- /docs/assets/dependencies/dat.gui.css: -------------------------------------------------------------------------------- 1 | .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;-o-transition:opacity .1s linear;-moz-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:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;-moz-transition:height .1s ease-out;transition:height .1s ease-out;-webkit-transition:overflow .1s linear;-o-transition:overflow .1s linear;-moz-transition:overflow .1s linear;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.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;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%;position:relative}.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:7px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .cr.color{overflow:visible}.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:0px 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 4px;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 rgba(255,255,255,0.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.function:hover,.dg .cr.boolean: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} 2 | -------------------------------------------------------------------------------- /docs/assets/dependencies/dat.gui-LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2014, Google Inc. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/assets/dependencies/dat.gui.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * dat-gui JavaScript Controller Library 3 | * http://code.google.com/p/dat-gui 4 | * 5 | * Copyright 2011 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&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.dat={})}(this,function(e){"use strict";function t(e,t){var n=e.__state.conversionName.toString(),o=Math.round(e.r),i=Math.round(e.g),r=Math.round(e.b),s=e.a,a=Math.round(e.h),l=e.s.toFixed(1),d=e.v.toFixed(1);if(t||"THREE_CHAR_HEX"===n||"SIX_CHAR_HEX"===n){for(var c=e.hex.toString(16);c.length<6;)c="0"+c;return"#"+c}return"CSS_RGB"===n?"rgb("+o+","+i+","+r+")":"CSS_RGBA"===n?"rgba("+o+","+i+","+r+","+s+")":"HEX"===n?"0x"+e.hex.toString(16):"RGB_ARRAY"===n?"["+o+","+i+","+r+"]":"RGBA_ARRAY"===n?"["+o+","+i+","+r+","+s+"]":"RGB_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+"}":"RGBA_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+",a:"+s+"}":"HSV_OBJ"===n?"{h:"+a+",s:"+l+",v:"+d+"}":"HSVA_OBJ"===n?"{h:"+a+",s:"+l+",v:"+d+",a:"+s+"}":"unknown format"}function n(e,t,n){Object.defineProperty(e,t,{get:function(){return"RGB"===this.__state.space?this.__state[t]:(I.recalculateRGB(this,t,n),this.__state[t])},set:function(e){"RGB"!==this.__state.space&&(I.recalculateRGB(this,t,n),this.__state.space="RGB"),this.__state[t]=e}})}function o(e,t){Object.defineProperty(e,t,{get:function(){return"HSV"===this.__state.space?this.__state[t]:(I.recalculateHSV(this),this.__state[t])},set:function(e){"HSV"!==this.__state.space&&(I.recalculateHSV(this),this.__state.space="HSV"),this.__state[t]=e}})}function i(e){if("0"===e||S.isUndefined(e))return 0;var t=e.match(U);return S.isNull(t)?0:parseFloat(t[1])}function r(e){var t=e.toString();return t.indexOf(".")>-1?t.length-t.indexOf(".")-1:0}function s(e,t){var n=Math.pow(10,t);return Math.round(e*n)/n}function a(e,t,n,o,i){return o+(e-t)/(n-t)*(i-o)}function l(e,t,n,o){e.style.background="",S.each(ee,function(i){e.style.cssText+="background: "+i+"linear-gradient("+t+", "+n+" 0%, "+o+" 100%); "})}function d(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%);"}function c(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 u(e){X.unbind(window,"resize",e.__resizeHandler),e.saveToLocalStorageIfPossible&&X.unbind(window,"unload",e.saveToLocalStorageIfPossible)}function _(e,t){var n=e.__preset_select[e.__preset_select.selectedIndex];n.innerHTML=t?n.value+"*":n.value}function h(e,t,n){if(n.__li=t,n.__gui=e,S.extend(n,{options:function(t){if(arguments.length>1){var o=n.__li.nextElementSibling;return n.remove(),f(e,n.object,n.property,{before:o,factoryArgs:[S.toArray(arguments)]})}if(S.isArray(t)||S.isObject(t)){var i=n.__li.nextElementSibling;return n.remove(),f(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(){return n.__gui.remove(n),n}}),n instanceof q){var o=new Q(n.object,n.property,{min:n.__min,max:n.__max,step:n.__step});S.each(["updateDisplay","onChange","onFinishChange","step","min","max"],function(e){var t=n[e],i=o[e];n[e]=o[e]=function(){var e=Array.prototype.slice.call(arguments);return i.apply(o,e),t.apply(n,e)}}),X.addClass(t,"has-slider"),n.domElement.insertBefore(o.domElement,n.domElement.firstElementChild)}else if(n instanceof Q){var i=function(t){if(S.isNumber(n.__min)&&S.isNumber(n.__max)){var o=n.__li.firstElementChild.firstElementChild.innerHTML,i=n.__gui.__listening.indexOf(n)>-1;n.remove();var r=f(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=S.compose(i,n.min),n.max=S.compose(i,n.max)}else n instanceof K?(X.bind(t,"click",function(){X.fakeEvent(n.__checkbox,"click")}),X.bind(n.__checkbox,"click",function(e){e.stopPropagation()})):n instanceof Z?(X.bind(t,"click",function(){X.fakeEvent(n.__button,"click")}),X.bind(t,"mouseover",function(){X.addClass(n.__button,"hover")}),X.bind(t,"mouseout",function(){X.removeClass(n.__button,"hover")})):n instanceof $&&(X.addClass(t,"color"),n.updateDisplay=S.compose(function(e){return t.style.borderLeftColor=n.__color.toString(),e},n.updateDisplay),n.updateDisplay());n.setValue=S.compose(function(t){return e.getRoot().__preset_select&&n.isModified()&&_(e.getRoot(),!0),t},n.setValue)}function p(e,t){var n=e.getRoot(),o=n.__rememberedObjects.indexOf(t.object);if(-1!==o){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,s=void 0;if(r[e.preset])s=r[e.preset];else{if(!r[se])return;s=r[se]}if(s[o]&&void 0!==s[o][t.property]){var a=s[o][t.property];t.initialValue=a,t.setValue(a)}}}}function f(e,t,n,o){if(void 0===t[n])throw new Error('Object "'+t+'" has no property "'+n+'"');var i=void 0;if(o.color)i=new $(t,n);else{var r=[t,n].concat(o.factoryArgs);i=ne.apply(e,r)}o.before instanceof z&&(o.before=o.before.__li),p(e,i),X.addClass(i.domElement,"c");var s=document.createElement("span");X.addClass(s,"property-name"),s.innerHTML=i.property;var a=document.createElement("div");a.appendChild(s),a.appendChild(i.domElement);var l=c(e,a,o.before);return X.addClass(l,he.CLASS_CONTROLLER_ROW),i instanceof $?X.addClass(l,"color"):X.addClass(l,H(i.getValue())),h(e,l,i),e.__controllers.push(i),i}function m(e,t){return document.location.href+"."+t}function g(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 b(e,t){t.style.display=e.useLocalStorage?"block":"none"}function v(e){var t=e.__save_row=document.createElement("li");X.addClass(e.domElement,"has-save"),e.__ul.insertBefore(t,e.__ul.firstChild),X.addClass(t,"save-row");var n=document.createElement("span");n.innerHTML=" ",X.addClass(n,"button gears");var o=document.createElement("span");o.innerHTML="Save",X.addClass(o,"button"),X.addClass(o,"save");var i=document.createElement("span");i.innerHTML="New",X.addClass(i,"button"),X.addClass(i,"save-as");var r=document.createElement("span");r.innerHTML="Revert",X.addClass(r,"button"),X.addClass(r,"revert");var s=e.__preset_select=document.createElement("select");if(e.load&&e.load.remembered?S.each(e.load.remembered,function(t,n){g(e,n,n===e.preset)}):g(e,se,!1),X.bind(s,"change",function(){for(var t=0;t=0;n--)t=[e[n].apply(this,t)];return t[0]}},each:function(e,t,n){if(e)if(A&&e.forEach&&e.forEach===A)e.forEach(t,n);else if(e.length===e.length+0){var o=void 0,i=void 0;for(o=0,i=e.length;o1?S.toArray(arguments):arguments[0];return S.each(O,function(t){if(t.litmus(e))return S.each(t.conversions,function(t,n){if(T=t.read(e),!1===L&&!1!==T)return L=T,T.conversionName=n,T.conversion=t,S.BREAK}),S.BREAK}),L},B=void 0,N={hsv_to_rgb:function(e,t,n){var o=Math.floor(e/60)%6,i=e/60-Math.floor(e/60),r=n*(1-t),s=n*(1-i*t),a=n*(1-(1-i)*t),l=[[n,a,r],[s,n,r],[r,n,a],[r,s,n],[a,r,n],[n,r,s]][o];return{r:255*l[0],g:255*l[1],b:255*l[2]}},rgb_to_hsv:function(e,t,n){var o=Math.min(e,t,n),i=Math.max(e,t,n),r=i-o,s=void 0,a=void 0;return 0===i?{h:NaN,s:0,v:0}:(a=r/i,s=e===i?(t-n)/r:t===i?2+(n-e)/r:4+(e-t)/r,(s/=6)<0&&(s+=1),{h:360*s,s:a,v:i/255})},rgb_to_hex:function(e,t,n){var o=this.hex_with_component(0,2,e);return o=this.hex_with_component(o,1,t),o=this.hex_with_component(o,0,n)},component_from_hex:function(e,t){return e>>8*t&255},hex_with_component:function(e,t,n){return n<<(B=8*t)|e&~(255<this.__max&&(n=this.__max),void 0!==this.__step&&n%this.__step!=0&&(n=Math.round(n/this.__step)*this.__step),j(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"setValue",this).call(this,n)}},{key:"min",value:function(e){return this.__min=e,this}},{key:"max",value:function(e){return this.__max=e,this}},{key:"step",value:function(e){return this.__step=e,this.__impliedStep=e,this.__precision=r(e),this}}]),t}(),Q=function(e){function t(e,n,o){function i(){l.__onFinishChange&&l.__onFinishChange.call(l,l.getValue())}function r(e){var t=d-e.clientY;l.setValue(l.getValue()+t*l.__impliedStep),d=e.clientY}function s(){X.unbind(window,"mousemove",r),X.unbind(window,"mouseup",s),i()}F(this,t);var a=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,o));a.__truncationSuspended=!1;var l=a,d=void 0;return a.__input=document.createElement("input"),a.__input.setAttribute("type","text"),X.bind(a.__input,"change",function(){var e=parseFloat(l.__input.value);S.isNaN(e)||l.setValue(e)}),X.bind(a.__input,"blur",function(){i()}),X.bind(a.__input,"mousedown",function(e){X.bind(window,"mousemove",r),X.bind(window,"mouseup",s),d=e.clientY}),X.bind(a.__input,"keydown",function(e){13===e.keyCode&&(l.__truncationSuspended=!0,this.blur(),l.__truncationSuspended=!1,i())}),a.updateDisplay(),a.domElement.appendChild(a.__input),a}return D(t,W),P(t,[{key:"updateDisplay",value:function(){return this.__input.value=this.__truncationSuspended?this.getValue():s(this.getValue(),this.__precision),j(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),q=function(e){function t(e,n,o,i,r){function s(e){e.preventDefault();var t=_.__background.getBoundingClientRect();return _.setValue(a(e.clientX,t.left,t.right,_.__min,_.__max)),!1}function l(){X.unbind(window,"mousemove",s),X.unbind(window,"mouseup",l),_.__onFinishChange&&_.__onFinishChange.call(_,_.getValue())}function d(e){var t=e.touches[0].clientX,n=_.__background.getBoundingClientRect();_.setValue(a(t,n.left,n.right,_.__min,_.__max))}function c(){X.unbind(window,"touchmove",d),X.unbind(window,"touchend",c),_.__onFinishChange&&_.__onFinishChange.call(_,_.getValue())}F(this,t);var u=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,{min:o,max:i,step:r})),_=u;return u.__background=document.createElement("div"),u.__foreground=document.createElement("div"),X.bind(u.__background,"mousedown",function(e){document.activeElement.blur(),X.bind(window,"mousemove",s),X.bind(window,"mouseup",l),s(e)}),X.bind(u.__background,"touchstart",function(e){1===e.touches.length&&(X.bind(window,"touchmove",d),X.bind(window,"touchend",c),d(e))}),X.addClass(u.__background,"slider"),X.addClass(u.__foreground,"slider-fg"),u.updateDisplay(),u.__background.appendChild(u.__foreground),u.domElement.appendChild(u.__background),u}return D(t,W),P(t,[{key:"updateDisplay",value:function(){var e=(this.getValue()-this.__min)/(this.__max-this.__min);return this.__foreground.style.width=100*e+"%",j(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),Z=function(e){function t(e,n,o){F(this,t);var i=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n)),r=i;return i.__button=document.createElement("div"),i.__button.innerHTML=void 0===o?"Fire":o,X.bind(i.__button,"click",function(e){return e.preventDefault(),r.fire(),!1}),X.addClass(i.__button,"button"),i.domElement.appendChild(i.__button),i}return D(t,z),P(t,[{key:"fire",value:function(){this.__onChange&&this.__onChange.call(this),this.getValue().call(this.object),this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())}}]),t}(),$=function(e){function t(e,n){function o(e){u(e),X.bind(window,"mousemove",u),X.bind(window,"touchmove",u),X.bind(window,"mouseup",r),X.bind(window,"touchend",r)}function i(e){_(e),X.bind(window,"mousemove",_),X.bind(window,"touchmove",_),X.bind(window,"mouseup",s),X.bind(window,"touchend",s)}function r(){X.unbind(window,"mousemove",u),X.unbind(window,"touchmove",u),X.unbind(window,"mouseup",r),X.unbind(window,"touchend",r),c()}function s(){X.unbind(window,"mousemove",_),X.unbind(window,"touchmove",_),X.unbind(window,"mouseup",s),X.unbind(window,"touchend",s),c()}function a(){var e=R(this.value);!1!==e?(p.__color.__state=e,p.setValue(p.__color.toOriginal())):this.value=p.__color.toString()}function c(){p.__onFinishChange&&p.__onFinishChange.call(p,p.__color.toOriginal())}function u(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=p.__saturation_field.getBoundingClientRect(),n=e.touches&&e.touches[0]||e,o=n.clientX,i=n.clientY,r=(o-t.left)/(t.right-t.left),s=1-(i-t.top)/(t.bottom-t.top);return s>1?s=1:s<0&&(s=0),r>1?r=1:r<0&&(r=0),p.__color.v=s,p.__color.s=r,p.setValue(p.__color.toOriginal()),!1}function _(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=p.__hue_field.getBoundingClientRect(),n=1-((e.touches&&e.touches[0]||e).clientY-t.top)/(t.bottom-t.top);return n>1?n=1:n<0&&(n=0),p.__color.h=360*n,p.setValue(p.__color.toOriginal()),!1}F(this,t);var h=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n));h.__color=new I(h.getValue()),h.__temp=new I(0);var p=h;h.domElement=document.createElement("div"),X.makeSelectable(h.domElement,!1),h.__selector=document.createElement("div"),h.__selector.className="selector",h.__saturation_field=document.createElement("div"),h.__saturation_field.className="saturation-field",h.__field_knob=document.createElement("div"),h.__field_knob.className="field-knob",h.__field_knob_border="2px solid ",h.__hue_knob=document.createElement("div"),h.__hue_knob.className="hue-knob",h.__hue_field=document.createElement("div"),h.__hue_field.className="hue-field",h.__input=document.createElement("input"),h.__input.type="text",h.__input_textShadow="0 1px 1px ",X.bind(h.__input,"keydown",function(e){13===e.keyCode&&a.call(this)}),X.bind(h.__input,"blur",a),X.bind(h.__selector,"mousedown",function(){X.addClass(this,"drag").bind(window,"mouseup",function(){X.removeClass(p.__selector,"drag")})}),X.bind(h.__selector,"touchstart",function(){X.addClass(this,"drag").bind(window,"touchend",function(){X.removeClass(p.__selector,"drag")})});var f=document.createElement("div");return S.extend(h.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}),S.extend(h.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:h.__field_knob_border+(h.__color.v<.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}),S.extend(h.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}),S.extend(h.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}),S.extend(f.style,{width:"100%",height:"100%",background:"none"}),l(f,"top","rgba(0,0,0,0)","#000"),S.extend(h.__hue_field.style,{width:"15px",height:"100px",border:"1px solid #555",cursor:"ns-resize",position:"absolute",top:"3px",right:"3px"}),d(h.__hue_field),S.extend(h.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:h.__input_textShadow+"rgba(0,0,0,0.7)"}),X.bind(h.__saturation_field,"mousedown",o),X.bind(h.__saturation_field,"touchstart",o),X.bind(h.__field_knob,"mousedown",o),X.bind(h.__field_knob,"touchstart",o),X.bind(h.__hue_field,"mousedown",i),X.bind(h.__hue_field,"touchstart",i),h.__saturation_field.appendChild(f),h.__selector.appendChild(h.__field_knob),h.__selector.appendChild(h.__saturation_field),h.__selector.appendChild(h.__hue_field),h.__hue_field.appendChild(h.__hue_knob),h.domElement.appendChild(h.__input),h.domElement.appendChild(h.__selector),h.updateDisplay(),h}return D(t,z),P(t,[{key:"updateDisplay",value:function(){var e=R(this.getValue());if(!1!==e){var t=!1;S.each(I.COMPONENTS,function(n){if(!S.isUndefined(e[n])&&!S.isUndefined(this.__color.__state[n])&&e[n]!==this.__color.__state[n])return t=!0,{}},this),t&&S.extend(this.__color.__state,e)}S.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;S.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(),S.extend(this.__input.style,{backgroundColor:this.__color.toHexString(),color:"rgb("+n+","+n+","+n+")",textShadow:this.__input_textShadow+"rgba("+o+","+o+","+o+",.7)"})}}]),t}(),ee=["-moz-","-o-","-webkit-","-ms-",""],te={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(e){}}},ne=function(e,t){var n=e[t];return S.isArray(arguments[2])||S.isObject(arguments[2])?new Y(e,t,arguments[2]):S.isNumber(n)?S.isNumber(arguments[2])&&S.isNumber(arguments[3])?S.isNumber(arguments[4])?new q(e,t,arguments[2],arguments[3],arguments[4]):new q(e,t,arguments[2],arguments[3]):S.isNumber(arguments[4])?new Q(e,t,{min:arguments[2],max:arguments[3],step:arguments[4]}):new Q(e,t,{min:arguments[2],max:arguments[3]}):S.isString(n)?new J(e,t):S.isFunction(n)?new Z(e,t,""):S.isBoolean(n)?new K(e,t):null},oe=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)},ie=function(){function e(){F(this,e),this.backgroundElement=document.createElement("div"),S.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"}),X.makeFullscreen(this.backgroundElement),this.backgroundElement.style.position="fixed",this.domElement=document.createElement("div"),S.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;X.bind(this.backgroundElement,"click",function(){t.hide()})}return P(e,[{key:"show",value: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.defer(function(){e.backgroundElement.style.opacity=1,e.domElement.style.opacity=1,e.domElement.style.webkitTransform="scale(1)"})}},{key:"hide",value:function(){var e=this,t=function t(){e.domElement.style.display="none",e.backgroundElement.style.display="none",X.unbind(e.domElement,"webkitTransitionEnd",t),X.unbind(e.domElement,"transitionend",t),X.unbind(e.domElement,"oTransitionEnd",t)};X.bind(this.domElement,"webkitTransitionEnd",t),X.bind(this.domElement,"transitionend",t),X.bind(this.domElement,"oTransitionEnd",t),this.backgroundElement.style.opacity=0,this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)"}},{key:"layout",value:function(){this.domElement.style.left=window.innerWidth/2-X.getWidth(this.domElement)/2+"px",this.domElement.style.top=window.innerHeight/2-X.getHeight(this.domElement)/2+"px"}}]),e}(),re=function(e){if(e&&"undefined"!=typeof window){var t=document.createElement("style");return t.setAttribute("type","text/css"),t.innerHTML=e,document.head.appendChild(t),e}}(".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;-o-transition:opacity .1s linear;-moz-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:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;-moz-transition:height .1s ease-out;transition:height .1s ease-out;-webkit-transition:overflow .1s linear;-o-transition:overflow .1s linear;-moz-transition:overflow .1s linear;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.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;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%;position:relative}.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:7px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .cr.color{overflow:visible}.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:0px 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 4px;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 rgba(255,255,255,0.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.function:hover,.dg .cr.boolean: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}\n");te.inject(re);var se="Default",ae=function(){try{return!!window.localStorage}catch(e){return!1}}(),le=void 0,de=!0,ce=void 0,ue=!1,_e=[],he=function e(t){var n=this,o=t||{};this.domElement=document.createElement("div"),this.__ul=document.createElement("ul"),this.domElement.appendChild(this.__ul),X.addClass(this.domElement,"dg"),this.__folders={},this.__controllers=[],this.__rememberedObjects=[],this.__rememberedObjectIndecesToControllers=[],this.__listening=[],o=S.defaults(o,{closeOnTop:!1,autoPlace:!0,width:e.DEFAULT_WIDTH}),o=S.defaults(o,{resizable:o.autoPlace,hideable:o.autoPlace}),S.isUndefined(o.load)?o.load={preset:se}:o.preset&&(o.load.preset=o.preset),S.isUndefined(o.parent)&&o.hideable&&_e.push(this),o.resizable=S.isUndefined(o.parent)&&o.resizable,o.autoPlace&&S.isUndefined(o.scrollable)&&(o.scrollable=!0);var i=ae&&"true"===localStorage.getItem(m(this,"isLocal")),r=void 0,s=void 0;if(Object.defineProperties(this,{parent:{get:function(){return o.parent}},scrollable:{get:function(){return o.scrollable}},autoPlace:{get:function(){return o.autoPlace}},closeOnTop:{get:function(){return o.closeOnTop}},preset:{get:function(){return n.parent?n.getRoot().preset:o.load.preset},set:function(e){n.parent?n.getRoot().preset=e:o.load.preset=e,E(this),n.revert()}},width:{get:function(){return o.width},set:function(e){o.width=e,w(n,e)}},name:{get:function(){return o.name},set:function(e){o.name=e,s&&(s.innerHTML=o.name)}},closed:{get:function(){return o.closed},set:function(t){o.closed=t,o.closed?X.addClass(n.__ul,e.CLASS_CLOSED):X.removeClass(n.__ul,e.CLASS_CLOSED),this.onResize(),n.__closeButton&&(n.__closeButton.innerHTML=t?e.TEXT_OPEN:e.TEXT_CLOSED)}},load:{get:function(){return o.load}},useLocalStorage:{get:function(){return i},set:function(e){ae&&(i=e,e?X.bind(window,"unload",r):X.unbind(window,"unload",r),localStorage.setItem(m(n,"isLocal"),e))}}}),S.isUndefined(o.parent)){if(this.closed=o.closed||!1,X.addClass(this.domElement,e.CLASS_MAIN),X.makeSelectable(this.domElement,!1),ae&&i){n.useLocalStorage=!0;var a=localStorage.getItem(m(this,"gui"));a&&(o.load=JSON.parse(a))}this.__closeButton=document.createElement("div"),this.__closeButton.innerHTML=e.TEXT_CLOSED,X.addClass(this.__closeButton,e.CLASS_CLOSE_BUTTON),o.closeOnTop?(X.addClass(this.__closeButton,e.CLASS_CLOSE_TOP),this.domElement.insertBefore(this.__closeButton,this.domElement.childNodes[0])):(X.addClass(this.__closeButton,e.CLASS_CLOSE_BOTTOM),this.domElement.appendChild(this.__closeButton)),X.bind(this.__closeButton,"click",function(){n.closed=!n.closed})}else{void 0===o.closed&&(o.closed=!0);var l=document.createTextNode(o.name);X.addClass(l,"controller-name"),s=c(n,l);X.addClass(this.__ul,e.CLASS_CLOSED),X.addClass(s,"title"),X.bind(s,"click",function(e){return e.preventDefault(),n.closed=!n.closed,!1}),o.closed||(this.closed=!1)}o.autoPlace&&(S.isUndefined(o.parent)&&(de&&(ce=document.createElement("div"),X.addClass(ce,"dg"),X.addClass(ce,e.CLASS_AUTO_PLACE_CONTAINER),document.body.appendChild(ce),de=!1),ce.appendChild(this.domElement),X.addClass(this.domElement,e.CLASS_AUTO_PLACE)),this.parent||w(n,o.width)),this.__resizeHandler=function(){n.onResizeDebounced()},X.bind(window,"resize",this.__resizeHandler),X.bind(this.__ul,"webkitTransitionEnd",this.__resizeHandler),X.bind(this.__ul,"transitionend",this.__resizeHandler),X.bind(this.__ul,"oTransitionEnd",this.__resizeHandler),this.onResize(),o.resizable&&y(this),r=function(){ae&&"true"===localStorage.getItem(m(n,"isLocal"))&&localStorage.setItem(m(n,"gui"),JSON.stringify(n.getSaveObject()))},this.saveToLocalStorageIfPossible=r,o.parent||function(){var e=n.getRoot();e.width+=1,S.defer(function(){e.width-=1})}()};he.toggleHide=function(){ue=!ue,S.each(_e,function(e){e.domElement.style.display=ue?"none":""})},he.CLASS_AUTO_PLACE="a",he.CLASS_AUTO_PLACE_CONTAINER="ac",he.CLASS_MAIN="main",he.CLASS_CONTROLLER_ROW="cr",he.CLASS_TOO_TALL="taller-than-window",he.CLASS_CLOSED="closed",he.CLASS_CLOSE_BUTTON="close-button",he.CLASS_CLOSE_TOP="close-top",he.CLASS_CLOSE_BOTTOM="close-bottom",he.CLASS_DRAG="drag",he.DEFAULT_WIDTH=245,he.TEXT_CLOSED="Close Controls",he.TEXT_OPEN="Open Controls",he._keydownHandler=function(e){"text"===document.activeElement.type||72!==e.which&&72!==e.keyCode||he.toggleHide()},X.bind(window,"keydown",he._keydownHandler,!1),S.extend(he.prototype,{add:function(e,t){return f(this,e,t,{factoryArgs:Array.prototype.slice.call(arguments,2)})},addColor:function(e,t){return f(this,e,t,{color:!0})},remove:function(e){this.__ul.removeChild(e.__li),this.__controllers.splice(this.__controllers.indexOf(e),1);var t=this;S.defer(function(){t.onResize()})},destroy:function(){if(this.parent)throw new Error("Only the root GUI should be removed with .destroy(). For subfolders, use gui.removeFolder(folder) instead.");this.autoPlace&&ce.removeChild(this.domElement);var e=this;S.each(this.__folders,function(t){e.removeFolder(t)}),X.unbind(window,"keydown",he._keydownHandler,!1),u(this)},addFolder:function(e){if(void 0!==this.__folders[e])throw new Error('You already have a folder in this GUI by the name "'+e+'"');var t={name:e,parent:this};t.autoPlace=this.autoPlace,this.load&&this.load.folders&&this.load.folders[e]&&(t.closed=this.load.folders[e].closed,t.load=this.load.folders[e]);var n=new he(t);this.__folders[e]=n;var o=c(this,n.domElement);return X.addClass(o,"folder"),n},removeFolder:function(e){this.__ul.removeChild(e.domElement.parentElement),delete this.__folders[e.name],this.load&&this.load.folders&&this.load.folders[e.name]&&delete this.load.folders[e.name],u(e);var t=this;S.each(e.__folders,function(t){e.removeFolder(t)}),S.defer(function(){t.onResize()})},open:function(){this.closed=!1},close:function(){this.closed=!0},hide:function(){this.domElement.style.display="none"},show:function(){this.domElement.style.display=""},onResize:function(){var e=this.getRoot();if(e.scrollable){var t=X.getOffset(e.__ul).top,n=0;S.each(e.__ul.childNodes,function(t){e.autoPlace&&t===e.__save_row||(n+=X.getHeight(t))}),window.innerHeight-t-20GUI\'s constructor:\n\n \n\n
\n\n Automatically save\n values to localStorage on exit.\n\n
The values saved to localStorage will\n override those passed to dat.GUI\'s constructor. This makes it\n easier to work incrementally, but localStorage is fragile,\n and your friends may not see the same values you do.\n\n
\n\n
\n\n'),this.parent)throw new Error("You can only call remember on a top level GUI.");var e=this;S.each(Array.prototype.slice.call(arguments),function(t){0===e.__rememberedObjects.length&&v(e),-1===e.__rememberedObjects.indexOf(t)&&e.__rememberedObjects.push(t)}),this.autoPlace&&w(this,this.width)},getRoot:function(){for(var e=this;e.parent;)e=e.parent;return e},getSaveObject:function(){var e=this.load;return e.closed=this.closed,this.__rememberedObjects.length>0&&(e.preset=this.preset,e.remembered||(e.remembered={}),e.remembered[this.preset]=x(this)),e.folders={},S.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]=x(this),_(this,!1),this.saveToLocalStorageIfPossible()},saveAs:function(e){this.load.remembered||(this.load.remembered={},this.load.remembered[se]=x(this,!0)),this.load.remembered[e]=x(this),this.preset=e,g(this,e,!0),this.saveToLocalStorageIfPossible()},revert:function(e){S.each(this.__controllers,function(t){this.getRoot().load.remembered?p(e||this.getRoot(),t):t.setValue(t.initialValue),t.__onFinishChange&&t.__onFinishChange.call(t,t.getValue())},this),S.each(this.__folders,function(e){e.revert(e)}),e||_(this.getRoot(),!1)},listen:function(e){var t=0===this.__listening.length;this.__listening.push(e),t&&C(this.__listening)},updateDisplay:function(){S.each(this.__controllers,function(e){e.updateDisplay()}),S.each(this.__folders,function(e){e.updateDisplay()})}});var pe={Color:I,math:N,interpret:R},fe={Controller:z,BooleanController:K,OptionController:Y,StringController:J,NumberController:W,NumberControllerBox:Q,NumberControllerSlider:q,FunctionController:Z,ColorController:$},me={dom:X},ge={GUI:he},be=he,ve={color:pe,controllers:fe,dom:me,gui:ge,GUI:be};e.color=pe,e.controllers=fe,e.dom=me,e.gui=ge,e.GUI=be,e.default=ve,Object.defineProperty(e,"__esModule",{value:!0})}); 14 | -------------------------------------------------------------------------------- /docs/assets/scripts/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2014 David Lettier 3 | lettier.com 4 | */ 5 | 6 | // The WebGL context. 7 | 8 | var gl; 9 | 10 | // The compiled and linked vertex and fragment shaders. 11 | 12 | var shaderProgram; 13 | 14 | // A stack for preserving matrix transformation states. 15 | 16 | var mvMatrixStack = [ ]; 17 | 18 | // Perspective or orthographic projection? 19 | 20 | var perspective_projection = true; 21 | 22 | // Model view and projection matrices. 23 | 24 | var mvMatrix = mat4.create( ); 25 | var pMatrix = mat4.create( ); 26 | 27 | // Isosurface data structures for holding the vertices, vertex normals, and vertex colors. 28 | 29 | var isosurfaceVertexPositionBuffer; 30 | var isosurfaceVertexNormalBuffer; 31 | var isosurfaceVertexColorBuffer; 32 | 33 | var isosurface1VertexPositionBuffer; 34 | var isosurface1VertexNormalBuffer; 35 | var isosurface1VertexColorBuffer; 36 | 37 | var pointLightSphereVertexPositionBuffer; 38 | var pointLightSphereVertexNormalBuffer; 39 | var pointLightSphereVertexColorBuffer; 40 | 41 | // Base color used for the ambient, fog, and clear-to colors. 42 | 43 | var base_color = [ 0.123, 0.154, 0.182 ]; 44 | 45 | // Lighting power. 46 | 47 | var lighting_power = 2; 48 | 49 | // Used for time based animation. 50 | 51 | var time_last = 0; 52 | 53 | // Used to rotate the isosurface. 54 | 55 | var rotation_radians = 0.0; 56 | var rotation_radians_step = 0.3; 57 | 58 | // Use lighting? 59 | 60 | var use_lighting = 1; 61 | 62 | // Use wireframe rendering? 63 | 64 | var use_wireframe = 0; 65 | 66 | // Render different buffers. 67 | 68 | var show_depth = 0; 69 | var show_normals = 0; 70 | var show_position = 0; 71 | 72 | // Alpha blending enabled? 73 | 74 | var alpha_blending_enabled = 0; 75 | 76 | // Normal map? 77 | 78 | var normal_map = 1; 79 | 80 | // Number of times initBuffers has been called. 81 | 82 | var init_buffers_called = 0; 83 | 84 | // Used to orbit the point lights. 85 | 86 | var point_light_theta = 1.57; 87 | var point_light_phi = 1.57; 88 | var point_light_theta_step = 0.39; 89 | var point_light_phi_step = 0.39; 90 | 91 | var point_light_theta1 = 1.57; 92 | var point_light_phi1 = 1.57; 93 | var point_light_theta_step1 = 0.3; 94 | var point_light_phi_step1 = 0.3; 95 | 96 | // Performs the draw loop iteration at roughly 60 frames per second. 97 | 98 | window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; 99 | 100 | // On-load event callback. 101 | 102 | window.onload = function ( ) { 103 | var gui = new dat.GUI(); 104 | 105 | gui.add(this, "lighting_power", 0, 5); 106 | gui.add(this, "perspective_projection", { On: true, Off: false }); 107 | gui.add(this, "use_lighting", { On: 1, Off: 0 }); 108 | gui.add(this, "use_wireframe", { On: 1, Off: 0 }); 109 | gui.add(this, "show_depth", { Yes: 1, No: 0 }); 110 | gui.add(this, "show_normals", { Yes: 1, No: 0 }); 111 | gui.add(this, "show_position", { Yes: 1, No: 0 }); 112 | gui.add(this, "normal_map", { On: 1, Off: 0 }); 113 | 114 | webGLStart( ); 115 | }; 116 | 117 | // Browser window re-size event callback. 118 | 119 | window.onresize = function ( ) { resize_contents( ); }; 120 | 121 | // Initializes the WebGL context. 122 | 123 | function initGL( canvas ) 124 | { 125 | 126 | try 127 | { 128 | 129 | gl = canvas.getContext( "webgl" ) || canvas.getContext( "experimental-webgl" ); 130 | 131 | gl.viewportWidth = canvas.width; 132 | gl.viewportHeight = canvas.height; 133 | 134 | } 135 | catch ( error ) 136 | { 137 | 138 | // Browser cannot initialize a WebGL context. 139 | 140 | window.location.assign( "http://get.webgl.org/" ); 141 | 142 | } 143 | 144 | if ( !gl ) 145 | { 146 | 147 | // Browser cannot initialize a WebGL context. 148 | 149 | window.location.assign( "http://get.webgl.org/" ); 150 | 151 | } 152 | 153 | } 154 | 155 | // Function to retrieve the shader strings thereby compiling them into shader programs run by the GPU. 156 | 157 | function getShader( gl, id ) 158 | { 159 | var shaderScript = document.getElementById( id ); 160 | 161 | if ( !shaderScript ) 162 | { 163 | 164 | console.error( "No shader scripts present." ); 165 | 166 | return null; 167 | 168 | } 169 | 170 | var str = ""; 171 | 172 | var k = shaderScript.firstChild; 173 | 174 | while ( k ) 175 | { 176 | 177 | if ( k.nodeType == 3 ) 178 | { 179 | 180 | str += k.textContent; 181 | 182 | } 183 | 184 | k = k.nextSibling; 185 | 186 | } 187 | 188 | var shader; 189 | 190 | if ( shaderScript.type == "x-shader/x-fragment" ) 191 | { 192 | 193 | shader = gl.createShader( gl.FRAGMENT_SHADER ); 194 | 195 | } 196 | else if ( shaderScript.type == "x-shader/x-vertex" ) 197 | { 198 | 199 | shader = gl.createShader( gl.VERTEX_SHADER ); 200 | 201 | } 202 | else 203 | { 204 | 205 | console.error( "No fragment/vertex shaders found." ); 206 | 207 | return null; 208 | 209 | } 210 | 211 | gl.shaderSource( shader, str ); 212 | 213 | gl.compileShader( shader ); 214 | 215 | if ( !gl.getShaderParameter( shader, gl.COMPILE_STATUS ) ) 216 | { 217 | 218 | console.error( gl.getShaderInfoLog( shader ) ); 219 | 220 | return null; 221 | 222 | } 223 | 224 | return shader; 225 | 226 | } 227 | 228 | // Initialize the vertex and fragment shaders. 229 | 230 | function initShaders( ) 231 | { 232 | 233 | var fragmentShader = getShader( gl, "shader-fs" ); 234 | var vertexShader = getShader( gl, "shader-vs" ); 235 | 236 | shaderProgram = gl.createProgram( ); 237 | 238 | gl.attachShader( shaderProgram, vertexShader ); 239 | gl.attachShader( shaderProgram, fragmentShader ); 240 | gl.linkProgram( shaderProgram ); 241 | 242 | if ( !gl.getProgramParameter( shaderProgram, gl.LINK_STATUS ) ) 243 | { 244 | 245 | console.error( "Could not initialize shaders." ); 246 | 247 | } 248 | 249 | gl.useProgram( shaderProgram ); 250 | 251 | // Acquire handles to shader program variables in order to pass data to the shaders. 252 | 253 | shaderProgram.vertexPositionAttribute = gl.getAttribLocation( shaderProgram, "aVertexPosition" ); 254 | gl.enableVertexAttribArray( shaderProgram.vertexPositionAttribute ); 255 | 256 | shaderProgram.vertexColorAttribute = gl.getAttribLocation( shaderProgram, "aVertexColor" ); 257 | gl.enableVertexAttribArray( shaderProgram.vertexColorAttribute ); 258 | 259 | shaderProgram.vertexNormalAttribute = gl.getAttribLocation( shaderProgram, "aVertexNormal" ); 260 | gl.enableVertexAttribArray( shaderProgram.vertexNormalAttribute ); 261 | 262 | shaderProgram.pMatrixUniform = gl.getUniformLocation( shaderProgram, "uPMatrix" ); 263 | shaderProgram.mvMatrixUniform = gl.getUniformLocation( shaderProgram, "uMVMatrix" ); 264 | shaderProgram.nMatrixUniform = gl.getUniformLocation( shaderProgram, "uNMatrix" ); 265 | 266 | shaderProgram.useLightingUniform = gl.getUniformLocation( shaderProgram, "uUseLighting" ); 267 | 268 | shaderProgram.alphaBlendingEnabled = gl.getUniformLocation( shaderProgram, "uAlphaBlendingEnabled" ); 269 | 270 | shaderProgram.normalMapEnabled = gl.getUniformLocation( shaderProgram, "uNormalMap" ); 271 | 272 | shaderProgram.perspectiveProjection = gl.getUniformLocation( shaderProgram, "uPerspectiveProjection" ); 273 | 274 | shaderProgram.showDepth = gl.getUniformLocation( shaderProgram, "uShowDepth" ); 275 | shaderProgram.showNormals = gl.getUniformLocation( shaderProgram, "uShowNormals" ); 276 | shaderProgram.showPosition = gl.getUniformLocation( shaderProgram, "uShowPosition" ); 277 | 278 | shaderProgram.ambientColorUniform = gl.getUniformLocation( shaderProgram, "uAmbientColor" ); 279 | 280 | shaderProgram.pointLightingLocationUniform = gl.getUniformLocation( shaderProgram, "uPointLightingLocation" ); 281 | shaderProgram.pointLightingColorUniform = gl.getUniformLocation( shaderProgram, "uPointLightingColor" ); 282 | 283 | shaderProgram.pointLightingLocationUniform1 = gl.getUniformLocation( shaderProgram, "uPointLightingLocation1" ); 284 | shaderProgram.pointLightingColorUniform1 = gl.getUniformLocation( shaderProgram, "uPointLightingColor1" ); 285 | 286 | } 287 | 288 | // Initialize all of the vertex, vertex normal, and vertex color buffers. 289 | 290 | function initBuffers( ) 291 | { 292 | 293 | // Generates one triangle complete with vertex normals and vertex colors. 294 | 295 | function triangle( p1, p2, p3, isosurface_function, resolution, invert_normals ) 296 | { 297 | 298 | // Push the vertices to this triangle face. 299 | // Pushing point 3, then 2, and then 1 so that the front face of the triangle 300 | // points outward from the surface. 301 | 302 | // Push point 1, then 2, and then 3 so that the front front face of the triangle 303 | // points inward from the surface. 304 | 305 | vertices.push( p3[ 0 ] ); vertices.push( p3[ 1 ] ); vertices.push( p3[ 2 ] ); 306 | vertices.push( p2[ 0 ] ); vertices.push( p2[ 1 ] ); vertices.push( p2[ 2 ] ); 307 | vertices.push( p1[ 0 ] ); vertices.push( p1[ 1 ] ); vertices.push( p1[ 2 ] ); 308 | 309 | // Calculate the isosurface gradient at point 1, 2, and 3 of the triangle. 310 | // These three gradient vectors are the vertex normals of this triangle. 311 | // This will provide a nice smooth appearance when the lighting is calculated. 312 | // These three gradient vectors will also be the vertex colors. 313 | 314 | var invert_normal = 1; 315 | 316 | if ( invert_normals === true ) invert_normal = -1; 317 | 318 | var vertext_color_alpha = 0.2; 319 | 320 | // Point 3. 321 | 322 | vertex_normal_x = 0.5 * ( isosurface_function( p3[ 0 ] + 1, p3[ 1 ], p3[ 2 ] ) - isosurface_function( p3[ 0 ] - 1, p3[ 1 ], p3[ 2 ] ) ) / resolution; 323 | vertex_normal_y = 0.5 * ( isosurface_function( p3[ 0 ], p3[ 1 ] + 1, p3[ 2 ] ) - isosurface_function( p3[ 0 ], p3[ 1 ] - 1, p3[ 2 ] ) ) / resolution; 324 | vertex_normal_z = 0.5 * ( isosurface_function( p3[ 0 ], p3[ 1 ], p3[ 2 ] + 1 ) - isosurface_function( p3[ 0 ], p3[ 1 ], p3[ 2 ] - 1 ) ) / resolution; 325 | 326 | vertex_normal_length = Math.sqrt( ( vertex_normal_x * vertex_normal_x ) + ( vertex_normal_y * vertex_normal_y ) + ( vertex_normal_z * vertex_normal_z ) ); 327 | 328 | if ( vertex_normal_length !== 0 ) 329 | { 330 | 331 | vertex_normal_x = vertex_normal_x / vertex_normal_length; 332 | vertex_normal_y = vertex_normal_y / vertex_normal_length; 333 | vertex_normal_z = vertex_normal_z / vertex_normal_length; 334 | 335 | } 336 | 337 | vertex_normals.push( invert_normal * vertex_normal_x ); vertex_normals.push( invert_normal * vertex_normal_y ); vertex_normals.push( invert_normal * vertex_normal_z ); 338 | 339 | // Push the vertex colors for this triangle face point. 340 | 341 | vertex_colors.push( 1.0 - vertex_normal_x ); vertex_colors.push( 1.0 - vertex_normal_y ); vertex_colors.push( 1.0 - vertex_normal_z ); vertex_colors.push( vertext_color_alpha ); 342 | 343 | // Point 2. 344 | 345 | vertex_normal_x = 0.5 * ( isosurface_function( p2[ 0 ] + 1, p2[ 1 ], p2[ 2 ] ) - isosurface_function( p2[ 0 ] - 1, p2[ 1 ], p2[ 2 ] ) ) / resolution; 346 | vertex_normal_y = 0.5 * ( isosurface_function( p2[ 0 ], p2[ 1 ] + 1, p2[ 2 ] ) - isosurface_function( p2[ 0 ], p2[ 1 ] - 1, p2[ 2 ] ) ) / resolution; 347 | vertex_normal_z = 0.5 * ( isosurface_function( p2[ 0 ], p2[ 1 ], p2[ 2 ] + 1 ) - isosurface_function( p2[ 0 ], p2[ 1 ], p2[ 2 ] - 1 ) ) / resolution; 348 | 349 | vertex_normal_length = Math.sqrt( ( vertex_normal_x * vertex_normal_x ) + ( vertex_normal_y * vertex_normal_y ) + ( vertex_normal_z * vertex_normal_z ) ); 350 | 351 | if ( vertex_normal_length !== 0 ) 352 | { 353 | 354 | vertex_normal_x = vertex_normal_x / vertex_normal_length; 355 | vertex_normal_y = vertex_normal_y / vertex_normal_length; 356 | vertex_normal_z = vertex_normal_z / vertex_normal_length; 357 | 358 | } 359 | 360 | vertex_normals.push( invert_normal * vertex_normal_x ); vertex_normals.push( invert_normal * vertex_normal_y ); vertex_normals.push( invert_normal * vertex_normal_z ); 361 | 362 | // Push the vertex colors for this triangle face point. 363 | 364 | vertex_colors.push( 1.0 - vertex_normal_x ); vertex_colors.push( 1.0 - vertex_normal_y ); vertex_colors.push( 1.0 - vertex_normal_z ); vertex_colors.push( vertext_color_alpha ); 365 | 366 | // Point 1. 367 | 368 | var vertex_normal_x = 0.5 * ( isosurface_function( p1[ 0 ] + 1, p1[ 1 ], p1[ 2 ] ) - isosurface_function( p1[ 0 ] - 1, p1[ 1 ], p1[ 2 ] ) ) / resolution; 369 | var vertex_normal_y = 0.5 * ( isosurface_function( p1[ 0 ], p1[ 1 ] + 1, p1[ 2 ] ) - isosurface_function( p1[ 0 ], p1[ 1 ] - 1, p1[ 2 ] ) ) / resolution; 370 | var vertex_normal_z = 0.5 * ( isosurface_function( p1[ 0 ], p1[ 1 ], p1[ 2 ] + 1 ) - isosurface_function( p1[ 0 ], p1[ 1 ], p1[ 2 ] - 1 ) ) / resolution; 371 | 372 | // Normalize. 373 | 374 | var vertex_normal_length = Math.sqrt( ( vertex_normal_x * vertex_normal_x ) + ( vertex_normal_y * vertex_normal_y ) + ( vertex_normal_z * vertex_normal_z ) ); 375 | 376 | if ( vertex_normal_length !== 0 ) 377 | { 378 | 379 | vertex_normal_x = vertex_normal_x / vertex_normal_length; 380 | vertex_normal_y = vertex_normal_y / vertex_normal_length; 381 | vertex_normal_z = vertex_normal_z / vertex_normal_length; 382 | 383 | } 384 | 385 | vertex_normals.push( invert_normal * vertex_normal_x ); vertex_normals.push( invert_normal * vertex_normal_y ); vertex_normals.push( invert_normal * vertex_normal_z ); 386 | 387 | // Push the vertex colors for this triangle face point. 388 | 389 | vertex_colors.push( 1.0 - vertex_normal_x ); vertex_colors.push( 1.0 - vertex_normal_y ); vertex_colors.push( 1.0 - vertex_normal_z ); vertex_colors.push( vertext_color_alpha ); 390 | 391 | } 392 | 393 | // The marching cubes algorithm. 394 | 395 | function marching_cubes( grid_min, grid_max, resolution, iso_level, isosurface_function, invert_normals ) 396 | { 397 | 398 | // Cube grid dimensions. 399 | 400 | var cube_grid_axis_min = grid_min; 401 | var cube_grid_axis_max = grid_max; 402 | 403 | // Generate the cube grid scalar field. 404 | 405 | /* 406 | 407 | j 408 | | 409 | | k 410 | | . 411 | | . 412 | | . 413 | | . 414 | | . 415 | |._________________i 416 | 417 | */ 418 | 419 | function Scalar_Point( x, y, z, value ) 420 | { 421 | 422 | this.id = x.toFixed( 2 ) + y.toFixed( 2 ) + z.toFixed( 2 ); 423 | 424 | this.x = x; 425 | this.y = y; 426 | this.z = z; 427 | this.value = value; 428 | 429 | } 430 | 431 | var scalar_points = { }; 432 | 433 | for ( var k = cube_grid_axis_min; k <= ( cube_grid_axis_max + resolution ); k += resolution ) 434 | { 435 | 436 | for ( var j = cube_grid_axis_min; j <= ( cube_grid_axis_max + resolution ); j += resolution ) 437 | { 438 | 439 | for ( var i = cube_grid_axis_min; i <= ( cube_grid_axis_max + resolution ); i += resolution ) 440 | { 441 | 442 | var x = i; 443 | var y = j; 444 | var z = k; 445 | 446 | var value = isosurface_function( x, y, z ); 447 | 448 | var scalar_point = new Scalar_Point( x, y, z, value ); 449 | 450 | scalar_points[ scalar_point.id ] = scalar_point; 451 | 452 | } 453 | 454 | } 455 | 456 | } 457 | 458 | function edge_intersection_interpolation( cube_va, cube_vb ) 459 | { 460 | 461 | if ( Math.abs( iso_level - cube_va.value ) < 0.00001 ) return [ cube_va.x, cube_va.y, cube_va.z ]; 462 | 463 | if ( Math.abs( iso_level - cube_vb.value ) < 0.00001 ) return [ cube_vb.x, cube_vb.y, cube_vb.z ]; 464 | 465 | if ( Math.abs( cube_va.value - cube_vb.value ) < 0.00001 ) return [ cube_va.x, cube_va.y, cube_va.z ]; 466 | 467 | var mean = ( iso_level - cube_va.value ) / ( cube_vb.value - cube_va.value ); 468 | 469 | var point = [ ]; 470 | 471 | point.push( cube_va.x + mean * ( cube_vb.x - cube_va.x ) ); 472 | point.push( cube_va.y + mean * ( cube_vb.y - cube_va.y ) ); 473 | point.push( cube_va.z + mean * ( cube_vb.z - cube_va.z ) ); 474 | 475 | return point; 476 | } 477 | 478 | for ( var k = cube_grid_axis_min; k < cube_grid_axis_max; k += resolution ) 479 | { 480 | 481 | for ( var j = cube_grid_axis_min; j < cube_grid_axis_max; j += resolution ) 482 | { 483 | 484 | for ( var i = cube_grid_axis_min; i < cube_grid_axis_max; i += resolution ) 485 | { 486 | 487 | // Perform the algorithm on one cube in the grid. 488 | 489 | // The cube's vertices. 490 | // There are eight of them. 491 | 492 | // 4---------5 493 | // /| /| 494 | // / | / | 495 | // 7---------6 | 496 | // | | | | 497 | // | 0------|--1 498 | // | / | / 499 | // |/ |/ 500 | // 3---------2 501 | 502 | var cube_v3 = scalar_points[ i.toFixed( 2 ) + j.toFixed( 2 ) + k.toFixed( 2 ) ]; // Lower left front corner. 503 | var cube_v2 = scalar_points[ ( i + resolution ).toFixed( 2 ) + j.toFixed( 2 ) + k.toFixed( 2 ) ]; // Lower right front corner. 504 | var cube_v6 = scalar_points[ ( i + resolution ).toFixed( 2 ) + ( j + resolution ).toFixed( 2 ) + k.toFixed( 2 ) ]; // Upper right front corner. 505 | var cube_v7 = scalar_points[ i.toFixed( 2 ) + ( j + resolution ).toFixed( 2 ) + k.toFixed( 2 ) ]; // Upper left front corner 506 | 507 | var cube_v0 = scalar_points[ i.toFixed( 2 ) + j.toFixed( 2 ) + ( k + resolution ).toFixed( 2 ) ]; // Lower left back corner. 508 | var cube_v1 = scalar_points[ ( i + resolution ).toFixed( 2 ) + j.toFixed( 2 ) + ( k + resolution ).toFixed( 2 ) ]; // Lower right back corner. 509 | var cube_v5 = scalar_points[ ( i + resolution ).toFixed( 2 ) + ( j + resolution ).toFixed( 2 ) + ( k + resolution ).toFixed( 2 ) ]; // Upper right back corner. 510 | var cube_v4 = scalar_points[ i.toFixed( 2 ) + ( j + resolution ).toFixed( 2 ) + ( k + resolution ).toFixed( 2 ) ]; // Upper left back corner. 511 | 512 | var cube_index = 0; 513 | 514 | if ( cube_v0.value < iso_level ) cube_index |= 1; 515 | if ( cube_v1.value < iso_level ) cube_index |= 2; 516 | if ( cube_v2.value < iso_level ) cube_index |= 4; 517 | if ( cube_v3.value < iso_level ) cube_index |= 8; 518 | if ( cube_v4.value < iso_level ) cube_index |= 16; 519 | if ( cube_v5.value < iso_level ) cube_index |= 32; 520 | if ( cube_v6.value < iso_level ) cube_index |= 64; 521 | if ( cube_v7.value < iso_level ) cube_index |= 128; 522 | 523 | // Does the isosurface not intersect any edges of the cube? 524 | 525 | if ( marching_cubes_edge_table[ cube_index ] === 0 ) continue; 526 | 527 | // What edges of the cube does the isosurface intersect? 528 | // For each cube edge intersected, interpolate an intersection vertex between the edge's incident vertices. 529 | // These vertices of intersection will form the triangle(s) that approximate the isosurface. 530 | 531 | // There are 12 edges in a cube. 532 | 533 | // 4----5----5 534 | // 8 /| 6/| 535 | // / |9 / | 10 536 | // 7----7----6 | 537 | // | | | | 538 | // 12 | 0---1--|--1 539 | // | / | / 540 | // |/ 4 11 |/ 2 541 | // 3----3----2 542 | // 543 | // 1={0,1}, 2={1,2}, 3={2,3}, 4={3,0}, 544 | // 5={4,5}, 6={5,6}, 7={6,7}, 8={7,4}, 545 | // 9={0,4}, 10={5,1}, 11={2,6}, 12={3,7} 546 | 547 | // Base ten slot: 2048 | 1024 | 512 | 256 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 548 | // Base two slot: 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 549 | // Edge slot: 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 550 | 551 | var vertices_of_intersection = [ ]; 552 | 553 | // Fill allocate the array. 554 | 555 | for ( var c = 0; c < 12; ++c ) 556 | { 557 | 558 | vertices_of_intersection.push( [ 0, 0, 0 ] ); 559 | 560 | } 561 | 562 | if ( marching_cubes_edge_table[ cube_index ] & 1 ) // Intersects edge one. 563 | { 564 | 565 | vertices_of_intersection[ 0 ] = edge_intersection_interpolation( cube_v0, cube_v1 ); 566 | 567 | } 568 | 569 | if ( marching_cubes_edge_table[ cube_index ] & 2 ) // Intersects edge two. 570 | { 571 | 572 | vertices_of_intersection[ 1 ] = edge_intersection_interpolation( cube_v1, cube_v2 ); 573 | 574 | } 575 | 576 | if ( marching_cubes_edge_table[ cube_index ] & 4 ) // Intersects edge three. 577 | { 578 | 579 | vertices_of_intersection[ 2 ] = edge_intersection_interpolation( cube_v2, cube_v3 ); 580 | 581 | } 582 | 583 | if ( marching_cubes_edge_table[ cube_index ] & 8 ) // Intersects edge four. 584 | { 585 | 586 | vertices_of_intersection[ 3 ] = edge_intersection_interpolation( cube_v3, cube_v0 ); 587 | 588 | } 589 | 590 | if ( marching_cubes_edge_table[ cube_index ] & 16 ) // Intersects edge five. 591 | { 592 | 593 | vertices_of_intersection[ 4 ] = edge_intersection_interpolation( cube_v4, cube_v5 ); 594 | 595 | } 596 | 597 | if ( marching_cubes_edge_table[ cube_index ] & 32 ) // Intersects edge six. 598 | { 599 | 600 | vertices_of_intersection[ 5 ] = edge_intersection_interpolation( cube_v5, cube_v6 ); 601 | 602 | } 603 | 604 | if ( marching_cubes_edge_table[ cube_index ] & 64 ) // Intersects edge seven. 605 | { 606 | 607 | vertices_of_intersection[ 6 ] = edge_intersection_interpolation( cube_v6, cube_v7 ); 608 | 609 | } 610 | 611 | if ( marching_cubes_edge_table[ cube_index ] & 128 ) // Intersects edge eight. 612 | { 613 | 614 | vertices_of_intersection[ 7 ] = edge_intersection_interpolation( cube_v7, cube_v4 ); 615 | 616 | } 617 | 618 | if ( marching_cubes_edge_table[ cube_index ] & 256 ) // Intersects edge nine. 619 | { 620 | 621 | vertices_of_intersection[ 8 ] = edge_intersection_interpolation( cube_v0, cube_v4 ); 622 | 623 | } 624 | 625 | if ( marching_cubes_edge_table[ cube_index ] & 512 ) // Intersects edge ten. 626 | { 627 | 628 | vertices_of_intersection[ 9 ] = edge_intersection_interpolation( cube_v1, cube_v5 ); 629 | 630 | } 631 | 632 | if ( marching_cubes_edge_table[ cube_index ] & 1024 ) // Intersects edge eleven. 633 | { 634 | 635 | vertices_of_intersection[ 10 ] = edge_intersection_interpolation( cube_v2, cube_v6 ); 636 | 637 | } 638 | 639 | if ( marching_cubes_edge_table[ cube_index ] & 2048 ) // Intersects edge twelve. 640 | { 641 | 642 | vertices_of_intersection[ 11 ] = edge_intersection_interpolation( cube_v3, cube_v7 ); 643 | 644 | } 645 | 646 | // Create the triangles. 647 | // Three vertices make up a triangle per iteration. 648 | 649 | for ( var a = 0; marching_cubes_triangle_table[ cube_index ][ a ] != -1; a = a + 3 ) 650 | { 651 | 652 | var v1 = vertices_of_intersection[ marching_cubes_triangle_table[ cube_index ][ a ] ]; 653 | var v2 = vertices_of_intersection[ marching_cubes_triangle_table[ cube_index ][ a + 1 ] ]; 654 | var v3 = vertices_of_intersection[ marching_cubes_triangle_table[ cube_index ][ a + 2 ] ]; 655 | 656 | triangle( v1, v2, v3, isosurface_function, resolution, invert_normals ); 657 | 658 | } 659 | 660 | } 661 | 662 | } 663 | 664 | } 665 | 666 | } 667 | 668 | // Begin creating the isosurfaces. 669 | 670 | // First isosurface. 671 | 672 | // Temporary arrays to hold all of the data that will be read into the buffers. 673 | 674 | var vertices = [ ]; 675 | var vertex_normals = [ ]; 676 | var vertex_colors = [ ]; 677 | 678 | function isosurface_function( x, y, z ) 679 | { 680 | 681 | // Goursat's surface. 682 | 683 | var x2 = x * x; 684 | var y2 = y * y; 685 | var z2 = z * z; 686 | 687 | var x4 = x2 * x2; 688 | var y4 = y2 * y2; 689 | var z4 = z2 * z2; 690 | 691 | var a = -1.0; 692 | var b = 0.0; 693 | var c = 0.5; 694 | 695 | var d = x2 + y2 + z2; 696 | var d2 = d * d; 697 | 698 | var value = x4 + y4 + z4 + a * d2 + b * d + c; 699 | 700 | return value; 701 | 702 | } 703 | 704 | // Grid min, grid max, resolution, iso-level, isosurface function, and invert normals. 705 | // Do not set the resolution to small. 706 | 707 | marching_cubes( -1.0, 1.0, 0.07, 0, isosurface_function, false ); 708 | 709 | // Create the vertex buffer and bind it getting it ready to read in the vertices to the isosurface. 710 | 711 | isosurfaceVertexPositionBuffer = gl.createBuffer( ); 712 | 713 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexPositionBuffer ); 714 | 715 | // Bind and fill the isosurface vertices. 716 | 717 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertices ), gl.STATIC_DRAW ); 718 | isosurfaceVertexPositionBuffer.itemSize = 3; 719 | isosurfaceVertexPositionBuffer.numItems = vertices.length / 3; 720 | 721 | // Bind and fill the isosurface vertex normals. 722 | 723 | isosurfaceVertexNormalBuffer = gl.createBuffer( ); 724 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexNormalBuffer ); 725 | 726 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_normals ), gl.STATIC_DRAW ); 727 | isosurfaceVertexNormalBuffer.itemSize = 3; 728 | isosurfaceVertexNormalBuffer.numItems = vertex_normals.length / 3; 729 | 730 | // Bind and fill the isosurface vertex colors. 731 | 732 | isosurfaceVertexColorBuffer = gl.createBuffer( ); 733 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexColorBuffer ); 734 | 735 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_colors ), gl.STATIC_DRAW ); 736 | isosurfaceVertexColorBuffer.itemSize = 4; 737 | isosurfaceVertexColorBuffer.numItems = vertex_colors.length / 4; 738 | 739 | // Second isosurface. 740 | 741 | if ( init_buffers_called === 0 ) 742 | { 743 | 744 | vertices = [ ]; 745 | vertex_normals = [ ]; 746 | vertex_colors = [ ]; 747 | 748 | function isosurface_function1( x, y, z ) 749 | { 750 | 751 | // The Taubin (heart) surface. 752 | 753 | // Swapped y and z from the standard formula. 754 | 755 | var x2 = x * x; 756 | var z2 = z * z; 757 | var y2 = y * y; 758 | var y3 = y * y * y; 759 | 760 | var a = x2 + ( 9 / 4 ) * z2 + y2 - 1; 761 | var a3 = a * a * a; 762 | 763 | var value = a3 - ( x2 * y3 ) - ( ( 9 / 80 ) * z2 * y3 ); 764 | 765 | return value; 766 | 767 | } 768 | 769 | // Grid min, grid max, resolution, iso-level, isosurface function, and invert normals. 770 | // Do not set the resolution to small. 771 | 772 | marching_cubes( -1.5, 1.5, 0.08, 0, isosurface_function1, false ); 773 | 774 | // Create the vertex buffer and bind it getting it ready to read in the vertices to the isosurface. 775 | 776 | isosurface1VertexPositionBuffer = gl.createBuffer( ); 777 | 778 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexPositionBuffer ); 779 | 780 | // Bind and fill the isosurface vertices. 781 | 782 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertices ), gl.STATIC_DRAW ); 783 | isosurface1VertexPositionBuffer.itemSize = 3; 784 | isosurface1VertexPositionBuffer.numItems = vertices.length / 3; 785 | 786 | // Bind and fill the isosurface vertex normals. 787 | 788 | isosurface1VertexNormalBuffer = gl.createBuffer( ); 789 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexNormalBuffer ); 790 | 791 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_normals ), gl.STATIC_DRAW ); 792 | isosurface1VertexNormalBuffer.itemSize = 3; 793 | isosurface1VertexNormalBuffer.numItems = vertex_normals.length / 3; 794 | 795 | // Bind and fill the isosurface vertex colors. 796 | 797 | isosurface1VertexColorBuffer = gl.createBuffer( ); 798 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexColorBuffer ); 799 | 800 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_colors ), gl.STATIC_DRAW ); 801 | isosurface1VertexColorBuffer.itemSize = 4; 802 | isosurface1VertexColorBuffer.numItems = vertex_colors.length / 4; 803 | 804 | } 805 | 806 | // Point light representation. 807 | 808 | if ( init_buffers_called === 0 ) // Do not recreate the point light sphere more than once. 809 | { 810 | 811 | vertices = [ ]; 812 | vertex_normals = [ ]; 813 | vertex_colors = [ ]; 814 | 815 | function isosurface_function2( x, y, z ) 816 | { 817 | 818 | // A sphere. 819 | 820 | var value = ( ( x - 0 ) * ( x - 0 ) ) + 821 | ( ( y - 0 ) * ( y - 0 ) ) + 822 | ( ( z - 0 ) * ( z - 0 ) ) - 823 | ( ( 0.5 ) * ( 0.5 ) ); 824 | 825 | return value; 826 | 827 | } 828 | 829 | // Grid min, grid max, resolution, iso-level, isosurface function, and invert normals. 830 | // Do not set the resolution to small. 831 | 832 | marching_cubes( -2, 2, 0.2, 0, isosurface_function2, false ); 833 | 834 | // Make the sphere bright white. 835 | 836 | for ( var i = 0; i < vertex_colors.length; i += 4 ) 837 | { 838 | 839 | vertex_colors[ i ] = 200.0; 840 | vertex_colors[ i + 1 ] = 200.0; 841 | vertex_colors[ i + 2 ] = 200.0; 842 | vertex_colors[ i + 3 ] = 1.0; 843 | 844 | } 845 | 846 | // Create the vertex buffer and bind it getting it ready to read in the vertices to the isosurface. 847 | 848 | pointLightSphereVertexPositionBuffer = gl.createBuffer( ); 849 | 850 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexPositionBuffer ); 851 | 852 | // Bind and fill the isosurface vertices. 853 | 854 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertices ), gl.STATIC_DRAW ); 855 | pointLightSphereVertexPositionBuffer.itemSize = 3; 856 | pointLightSphereVertexPositionBuffer.numItems = vertices.length / 3; 857 | 858 | // Bind and fill the isosurface vertex normals. 859 | 860 | pointLightSphereVertexNormalBuffer = gl.createBuffer( ); 861 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexNormalBuffer ); 862 | 863 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_normals ), gl.STATIC_DRAW ); 864 | pointLightSphereVertexNormalBuffer.itemSize = 3; 865 | pointLightSphereVertexNormalBuffer.numItems = vertex_normals.length / 3; 866 | 867 | // Bind and fill the isosurface vertex colors. 868 | 869 | pointLightSphereVertexColorBuffer = gl.createBuffer( ); 870 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexColorBuffer ); 871 | 872 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_colors ), gl.STATIC_DRAW ); 873 | pointLightSphereVertexColorBuffer.itemSize = 4; 874 | pointLightSphereVertexColorBuffer.numItems = vertex_colors.length / 4; 875 | 876 | } 877 | 878 | init_buffers_called += 1; 879 | 880 | } 881 | 882 | function initHUD( ) 883 | { 884 | 885 | // Create and show an onscreen logo. 886 | 887 | var logo_box = document.createElement( "div" ); 888 | logo_box.id = "logo_box"; 889 | logo_box.title = "Lettier"; 890 | logo_box.className = "logo_box"; 891 | logo_box.innerHTML = ""; 892 | 893 | document.body.appendChild( logo_box ); 894 | 895 | var logo_image = document.getElementById( "logo" ); 896 | logo_image_height = logo_image.clientHeight * 0.5; 897 | logo_image_width = logo_image.clientWidth * 0.5; 898 | logo_image.style.height = logo_image_height + "px"; 899 | logo_image.style.width = logo_image_width + "px"; 900 | logo_box.style.top = window.innerHeight - logo_image_height - 10 + "px"; 901 | logo_box.style.left = window.innerWidth - logo_image_width - 10 + "px"; 902 | 903 | } 904 | 905 | // Pass to the vertex shader the needed matrices. 906 | 907 | function setMatrixUniforms( ) 908 | { 909 | 910 | // Pass the vertex shader the projection matrix and the model-view matrix. 911 | 912 | gl.uniformMatrix4fv( shaderProgram.pMatrixUniform, false, pMatrix ); 913 | gl.uniformMatrix4fv( shaderProgram.mvMatrixUniform, false, mvMatrix ); 914 | 915 | // Pass the vertex normal matrix to the shader so it can compute the lighting calculations. 916 | 917 | var normalMatrix = mat3.create( ); 918 | mat3.normalFromMat4( normalMatrix, mvMatrix ); 919 | gl.uniformMatrix3fv( shaderProgram.nMatrixUniform, false, normalMatrix ); 920 | 921 | } 922 | 923 | function mvPushMatrix( ) 924 | { 925 | 926 | // Save the model view matrix for later use. 927 | 928 | var copy = mat4.create( ); 929 | copy = mat4.copy( copy, mvMatrix ); 930 | mvMatrixStack.push( copy ); 931 | 932 | } 933 | 934 | function mvPopMatrix( ) 935 | { 936 | 937 | // Gather the previously pushed model view matrix. 938 | 939 | if ( mvMatrixStack.length === 0 ) 940 | { 941 | 942 | console.error( "mvMatrixStack empty." ); 943 | 944 | } 945 | 946 | mvMatrix = mvMatrixStack.pop( ); 947 | } 948 | 949 | // The function renders the isosurfaces lit with the point light. 950 | // It also animates the rotation of the isosurfaces. 951 | 952 | function drawScene( timestamp ) 953 | { 954 | 955 | // Call this function to draw the next frame. 956 | 957 | window.requestAnimationFrame( drawScene ); 958 | 959 | // Time based animation instead of frame based animation. 960 | 961 | var time_now = new Date( ).getTime( ); 962 | 963 | if ( time_last !== 0 ) 964 | { 965 | 966 | var time_delta = ( time_now - time_last ) / 1000.0; 967 | 968 | rotation_radians += rotation_radians_step * time_delta; 969 | 970 | if ( rotation_radians > ( Math.PI * 2 ) ) rotation_radians = 0.0; 971 | 972 | if ( Number(use_lighting) === 1 ) 973 | { 974 | 975 | point_light_theta += point_light_theta_step * time_delta; 976 | point_light_phi += point_light_phi_step * time_delta; 977 | 978 | if ( point_light_theta > ( Math.PI * 2 ) ) point_light_theta = 0.0; 979 | if ( point_light_phi > ( Math.PI * 2 ) ) point_light_phi = 0.0; 980 | 981 | point_light_theta1 += point_light_theta_step1 * time_delta; 982 | point_light_phi1 += point_light_phi_step1 * time_delta; 983 | 984 | if ( point_light_theta1 > ( Math.PI * 2 ) ) point_light_theta1 = 0.0; 985 | if ( point_light_phi1 > ( Math.PI * 2 ) ) point_light_phi1 = 0.0; 986 | 987 | } 988 | 989 | } 990 | 991 | time_last = time_now; 992 | 993 | // Set the size of and clear the render window. 994 | 995 | gl.viewport( 0, 0, gl.viewportWidth, gl.viewportHeight ); 996 | 997 | gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT ); 998 | 999 | // Create the projection matrix. 1000 | 1001 | var near = 0.1; 1002 | var far = 50.0; 1003 | var fov_d = 55.0; 1004 | var fov_r = 55 * ( Math.PI / 180.0 ); 1005 | 1006 | if ( JSON.parse(perspective_projection) ) 1007 | { 1008 | 1009 | // Resulting perspective matrix, FOV in radians, aspect ratio, near, and far clipping plane. 1010 | 1011 | mat4.perspective( pMatrix, fov_r, gl.viewportWidth / gl.viewportHeight, near, far ); 1012 | 1013 | // Let the fragment shader know that perspective projection is being used. 1014 | 1015 | gl.uniform1i( shaderProgram.perspectiveProjection, 1 ); 1016 | 1017 | } 1018 | else 1019 | { 1020 | 1021 | // The goal is to have the object be about the same size in the window 1022 | // during orthographic project as it is during perspective projection. 1023 | 1024 | var a = gl.viewportWidth / gl.viewportHeight; // Window aspect ratio. 1025 | var h = 2 * ( 25 * Math.tan( fov_r / 2 ) ); // 25 is the absolute distance from the world origin to all of the isosurfaces' local origins. 1026 | var w = h * a; // Knowing the new window height size, get the new window width size based on the aspect ratio. 1027 | 1028 | // The canvas' origin is the upper left corner. To the right is the positive x-axis. 1029 | // Going down is the positive y-axis. 1030 | 1031 | // Any object at the world origin would appear at the upper left hand corner. 1032 | // Shift the origin to the middle of the screen. 1033 | 1034 | // Also, invert the y-axis as WebgL's positive y-axis points up while the canvas' positive 1035 | // y-axis points down the screen. 1036 | 1037 | // (0,O)------------------------(w,0) 1038 | // | | 1039 | // | | 1040 | // | | 1041 | // (0,h)------------------------(w,h) 1042 | // 1043 | // (-(w/2),(h/2))------------------------((w/2),(h/2)) 1044 | // | | 1045 | // | (0,0) | 1046 | // | | 1047 | // (-(w/2),-(h/2))------------------------((w/2),-(h/2)) 1048 | 1049 | // Resulting perspective matrix, left, right, bottom, top, near, and far clipping plane. 1050 | 1051 | mat4.ortho( 1052 | 1053 | pMatrix, 1054 | -( w / 2 ), 1055 | ( w / 2 ), 1056 | -( h / 2 ), 1057 | ( h / 2 ), 1058 | near, 1059 | far 1060 | 1061 | ); 1062 | 1063 | // Let the fragment shader know that orthographic projection is being used. 1064 | 1065 | gl.uniform1i( shaderProgram.perspectiveProjection, 0 ); 1066 | 1067 | } 1068 | 1069 | // Render different buffers to screen. 1070 | 1071 | gl.uniform1i( shaderProgram.showDepth, show_depth ); 1072 | gl.uniform1i( shaderProgram.showNormals, show_normals ); 1073 | gl.uniform1i( shaderProgram.showPosition, show_position ); 1074 | 1075 | // Move to the 3D space origin. 1076 | 1077 | mat4.identity( mvMatrix ); 1078 | 1079 | // Disable alpha blending. 1080 | 1081 | gl.disable( gl.BLEND ); 1082 | 1083 | alpha_blending_enabled = 0; 1084 | 1085 | gl.uniform1i( shaderProgram.alphaBlendingEnabled, alpha_blending_enabled ); 1086 | 1087 | if ( Number(use_lighting) === 1 ) 1088 | { 1089 | 1090 | // Pass the lighting parameters to the fragment shader. 1091 | 1092 | // Global ambient color. 1093 | 1094 | gl.uniform3f( shaderProgram.ambientColorUniform, base_color[ 0 ], base_color[ 1 ], base_color[ 2 ] ); 1095 | 1096 | // Point light 1. 1097 | 1098 | var point_light_position_x = 0 + 13.5 * Math.cos( point_light_theta ) * Math.sin( point_light_phi ); 1099 | var point_light_position_y = 0 + 13.5 * Math.sin( point_light_theta ) * Math.sin( point_light_phi ); 1100 | var point_light_position_z = -25 + 13.5 * Math.cos( point_light_phi ); 1101 | 1102 | gl.uniform3f( shaderProgram.pointLightingColorUniform, lighting_power, lighting_power, lighting_power ); 1103 | 1104 | gl.uniform3f( shaderProgram.pointLightingLocationUniform, point_light_position_x, point_light_position_y, point_light_position_z ); 1105 | 1106 | // Point light 2. 1107 | 1108 | var point_light_position_x1 = 0 + 8.0 * Math.cos( point_light_theta1 ) * Math.sin( point_light_phi1 ); 1109 | var point_light_position_y1 = 0 + 8.0 * Math.sin( point_light_theta1 ) * Math.sin( point_light_phi1 ); 1110 | var point_light_position_z1 = -25 + 8.0 * Math.cos( point_light_phi1 ); 1111 | 1112 | gl.uniform3f( shaderProgram.ambientColorUniform1, base_color[ 0 ], base_color[ 1 ], base_color[ 2 ] ); 1113 | 1114 | gl.uniform3f( shaderProgram.pointLightingColorUniform1, lighting_power, lighting_power, lighting_power ); 1115 | 1116 | gl.uniform3f( shaderProgram.pointLightingLocationUniform1, point_light_position_x1, point_light_position_y1, point_light_position_z1 ); 1117 | 1118 | // Turn off lighting for a moment so that the point light isosurface is 1119 | // bright simulating that the light is emanating from the surface. 1120 | 1121 | use_lighting = 0; 1122 | 1123 | gl.uniform1i( shaderProgram.useLightingUniform, use_lighting ); 1124 | 1125 | // Point light surfaces. 1126 | 1127 | // Save the model view matrix state. 1128 | 1129 | mvPushMatrix( ); 1130 | 1131 | // Point light surface 1. 1132 | 1133 | mat4.translate( mvMatrix, mvMatrix, [ point_light_position_x, point_light_position_y, point_light_position_z ] ); 1134 | 1135 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexPositionBuffer ); 1136 | gl.vertexAttribPointer( shaderProgram.vertexPositionAttribute, pointLightSphereVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1137 | 1138 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexNormalBuffer ); 1139 | gl.vertexAttribPointer( shaderProgram.vertexNormalAttribute, pointLightSphereVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1140 | 1141 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexColorBuffer ); 1142 | gl.vertexAttribPointer( shaderProgram.vertexColorAttribute, pointLightSphereVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1143 | 1144 | setMatrixUniforms( ); 1145 | 1146 | gl.drawArrays( gl.TRIANGLES, 0, pointLightSphereVertexPositionBuffer.numItems ); 1147 | 1148 | mvPopMatrix( ); 1149 | 1150 | // Save the model view matrix state. 1151 | 1152 | mvPushMatrix( ); 1153 | 1154 | // Point light surface 2. 1155 | 1156 | mat4.translate( mvMatrix, mvMatrix, [ point_light_position_x1, point_light_position_y1, point_light_position_z1 ] ); 1157 | 1158 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexPositionBuffer ); 1159 | gl.vertexAttribPointer( shaderProgram.vertexPositionAttribute, pointLightSphereVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1160 | 1161 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexNormalBuffer ); 1162 | gl.vertexAttribPointer( shaderProgram.vertexNormalAttribute, pointLightSphereVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1163 | 1164 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexColorBuffer ); 1165 | gl.vertexAttribPointer( shaderProgram.vertexColorAttribute, pointLightSphereVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1166 | 1167 | setMatrixUniforms( ); 1168 | 1169 | gl.drawArrays( gl.TRIANGLES, 0, pointLightSphereVertexPositionBuffer.numItems ); 1170 | 1171 | mvPopMatrix( ); 1172 | 1173 | use_lighting = 1; 1174 | 1175 | } 1176 | 1177 | // Move down the negative z-axis by 25 units. 1178 | 1179 | mat4.translate( mvMatrix, mvMatrix, [ 0.0, 0.0, -25.0 ] ); 1180 | 1181 | // Save the model view matrix state. 1182 | 1183 | mvPushMatrix( ); 1184 | 1185 | // Use lighting if enabled. 1186 | 1187 | gl.uniform1i( shaderProgram.useLightingUniform, Number(use_lighting) ); 1188 | 1189 | // If normal map is enabled. 1190 | 1191 | gl.uniform1i( shaderProgram.normalMapEnabled, normal_map ); 1192 | 1193 | // Second isosurface. 1194 | 1195 | // Scale up the surface in all dimensions. 1196 | 1197 | mat4.scale( mvMatrix, mvMatrix, [ 5.0, 5.0, 5.0 ] ); 1198 | 1199 | // Rotate around the y-axis. 1200 | 1201 | mat4.rotate( mvMatrix, mvMatrix, -rotation_radians, [ 0, 1, 0 ] ); 1202 | 1203 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexPositionBuffer ); 1204 | gl.vertexAttribPointer( shaderProgram.vertexPositionAttribute, isosurface1VertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1205 | 1206 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexNormalBuffer ); 1207 | gl.vertexAttribPointer( shaderProgram.vertexNormalAttribute, isosurface1VertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1208 | 1209 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexColorBuffer ); 1210 | gl.vertexAttribPointer( shaderProgram.vertexColorAttribute, isosurface1VertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1211 | 1212 | setMatrixUniforms( ); 1213 | 1214 | if ( Number(use_wireframe) === 0 ) 1215 | { 1216 | 1217 | gl.drawArrays( gl.TRIANGLES, 0, isosurface1VertexPositionBuffer.numItems ); 1218 | 1219 | } 1220 | else 1221 | { 1222 | 1223 | gl.drawArrays( gl.LINES, 0, isosurface1VertexPositionBuffer.numItems ); 1224 | 1225 | } 1226 | 1227 | // Restore the model view matrix state. 1228 | 1229 | mvPopMatrix( ); 1230 | 1231 | // Enable alpha blending. 1232 | 1233 | gl.blendFunc( gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); 1234 | 1235 | gl.enable( gl.BLEND ); 1236 | 1237 | alpha_blending_enabled = 1; 1238 | 1239 | gl.uniform1i( shaderProgram.alphaBlendingEnabled, alpha_blending_enabled ); 1240 | 1241 | // Save the current model view matrix for later use. 1242 | 1243 | mvPushMatrix( ); 1244 | 1245 | // First isosurface. 1246 | 1247 | mat4.scale( mvMatrix, mvMatrix, [ 11.0, 11.0, 11.0 ] ); 1248 | 1249 | // Rotate the model view matrix thereby rotating the isosurface. 1250 | 1251 | mat4.rotate( mvMatrix, mvMatrix, rotation_radians, [ 1, 1, 0 ] ); 1252 | 1253 | // Pass to the vertex shader the isosurface data. 1254 | 1255 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexPositionBuffer ); 1256 | gl.vertexAttribPointer( shaderProgram.vertexPositionAttribute, isosurfaceVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1257 | 1258 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexNormalBuffer ); 1259 | gl.vertexAttribPointer( shaderProgram.vertexNormalAttribute, isosurfaceVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1260 | 1261 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexColorBuffer ); 1262 | gl.vertexAttribPointer( shaderProgram.vertexColorAttribute, isosurfaceVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1263 | 1264 | setMatrixUniforms( ); 1265 | 1266 | // Render the isosurface to the screen. 1267 | 1268 | if ( Number(use_wireframe) === 0 ) 1269 | { 1270 | 1271 | gl.drawArrays( gl.TRIANGLES, 0, isosurfaceVertexPositionBuffer.numItems ); 1272 | 1273 | } 1274 | else 1275 | { 1276 | 1277 | gl.drawArrays( gl.LINES, 0, isosurfaceVertexPositionBuffer.numItems ); 1278 | 1279 | } 1280 | 1281 | // Get back the old model view matrix. 1282 | 1283 | mvPopMatrix( ); 1284 | 1285 | } 1286 | 1287 | function resize_contents( ) 1288 | { 1289 | 1290 | // The browser window has been re-sized so re-size the render window and onscreen elements. 1291 | 1292 | var logo_image = document.getElementById( "logo" ); 1293 | logo_image_height = logo_image.clientHeight; 1294 | logo_image_width = logo_image.clientWidth; 1295 | 1296 | var logo_box = document.getElementById( "logo_box" ); 1297 | logo_box.style.top = window.innerHeight - logo_image_height - 10 + "px"; 1298 | logo_box.style.left = window.innerWidth - logo_image_width - 10 + "px"; 1299 | 1300 | var canvas = document.getElementById( "webgl_canvas" ); 1301 | canvas.width = window.innerWidth; 1302 | canvas.height = window.innerHeight; 1303 | 1304 | gl.viewportWidth = canvas.width; 1305 | gl.viewportHeight = canvas.height; 1306 | 1307 | } 1308 | 1309 | function webGLStart( ) 1310 | { 1311 | 1312 | // Create and add the canvas that will be "painted" on or rather rendered to by WebGL. 1313 | 1314 | var canvas = document.createElement( "canvas" ); 1315 | canvas.id = "webgl_canvas"; 1316 | canvas.width = window.innerWidth; 1317 | canvas.height = window.innerHeight; 1318 | document.body.appendChild( canvas ); 1319 | 1320 | // Vertex shader GLSL code. 1321 | 1322 | var vertex_shader = document.createElement( "script" ); 1323 | vertex_shader.id = "shader-vs"; 1324 | vertex_shader.type = "x-shader/x-vertex"; 1325 | vertex_shader.innerHTML = "precision mediump float;"; 1326 | vertex_shader.innerHTML += "attribute vec3 aVertexPosition;"; 1327 | vertex_shader.innerHTML += "attribute vec3 aVertexNormal;"; 1328 | vertex_shader.innerHTML += "attribute vec4 aVertexColor;"; 1329 | vertex_shader.innerHTML += "uniform mat4 uMVMatrix;"; 1330 | vertex_shader.innerHTML += "uniform mat4 uPMatrix;"; 1331 | vertex_shader.innerHTML += "uniform mat3 uNMatrix;"; 1332 | vertex_shader.innerHTML += "varying vec4 vPosition;"; 1333 | vertex_shader.innerHTML += "varying vec4 vDiffuseColor;"; 1334 | vertex_shader.innerHTML += "varying vec3 vTransformedNormal;"; 1335 | vertex_shader.innerHTML += "void main( void ) {"; 1336 | vertex_shader.innerHTML += " vDiffuseColor = aVertexColor;"; 1337 | vertex_shader.innerHTML += " vTransformedNormal = uNMatrix * aVertexNormal;"; 1338 | vertex_shader.innerHTML += " vPosition = uMVMatrix * vec4( aVertexPosition, 1.0 );"; 1339 | vertex_shader.innerHTML += " gl_Position = uPMatrix * vPosition;"; 1340 | vertex_shader.innerHTML += "}"; 1341 | document.body.appendChild( vertex_shader ); 1342 | 1343 | // Fragment shader GLSL code. 1344 | 1345 | var fragment_shader = document.createElement( "script" ); 1346 | fragment_shader.id = "shader-fs"; 1347 | fragment_shader.type = "x-shader/x-fragment"; 1348 | fragment_shader.innerHTML = "precision mediump float;"; 1349 | fragment_shader.innerHTML += "uniform mat4 uPMatrix;"; 1350 | fragment_shader.innerHTML += "uniform bool uUseLighting;"; 1351 | fragment_shader.innerHTML += "uniform bool uAlphaBlendingEnabled;"; 1352 | fragment_shader.innerHTML += "uniform bool uShowDepth;"; 1353 | fragment_shader.innerHTML += "uniform bool uShowNormals;"; 1354 | fragment_shader.innerHTML += "uniform bool uShowPosition;"; 1355 | fragment_shader.innerHTML += "uniform bool uPerspectiveProjection;"; 1356 | fragment_shader.innerHTML += "uniform bool uNormalMap;"; 1357 | fragment_shader.innerHTML += "uniform vec3 uAmbientColor;"; 1358 | fragment_shader.innerHTML += "uniform vec3 uPointLightingLocation;"; 1359 | fragment_shader.innerHTML += "uniform vec3 uPointLightingColor;"; 1360 | fragment_shader.innerHTML += "uniform vec3 uPointLightingLocation1;"; 1361 | fragment_shader.innerHTML += "uniform vec3 uPointLightingColor1;"; 1362 | fragment_shader.innerHTML += "varying vec4 vPosition;"; 1363 | fragment_shader.innerHTML += "varying vec3 vTransformedNormal;"; 1364 | fragment_shader.innerHTML += "varying vec4 vDiffuseColor;"; 1365 | fragment_shader.innerHTML += "void main( void ) {"; 1366 | fragment_shader.innerHTML += " vec3 uAmbientColor = pow(uAmbientColor, vec3(2.2));"; 1367 | fragment_shader.innerHTML += " vec4 vDiffuseColor = vDiffuseColor;"; 1368 | fragment_shader.innerHTML += " vDiffuseColor.rgb = pow(vDiffuseColor.rgb, vec3(2.2));"; 1369 | fragment_shader.innerHTML += " vec3 uPointLightingColor = pow(uPointLightingColor, vec3(2.2));"; 1370 | fragment_shader.innerHTML += " vec3 uPointLightingColor1 = pow(uPointLightingColor1, vec3(2.2));"; 1371 | fragment_shader.innerHTML += " vec4 fog_color = vec4( " + base_color[ 0 ] + ", " + base_color[ 1 ] + ", " + base_color[ 2 ] + ", 1.0 );"; 1372 | fragment_shader.innerHTML += " fog_color.rgb = pow(fog_color.rgb, vec3(2.2));"; 1373 | fragment_shader.innerHTML += " vec3 ambient = vDiffuseColor.rgb * uAmbientColor;"; 1374 | fragment_shader.innerHTML += " vec3 color = ambient;"; 1375 | fragment_shader.innerHTML += " if ( uUseLighting ) {"; 1376 | fragment_shader.innerHTML += " vec3 light_direction = normalize( uPointLightingLocation - vPosition.xyz );"; 1377 | fragment_shader.innerHTML += " vec3 light_direction1 = normalize( uPointLightingLocation1 - vPosition.xyz );"; 1378 | fragment_shader.innerHTML += " vec3 eye_direction = -normalize( vPosition.xyz );"; 1379 | fragment_shader.innerHTML += " vec3 half_vector = normalize(light_direction + eye_direction);"; 1380 | fragment_shader.innerHTML += " vec3 half_vector1 = normalize(light_direction1 + eye_direction);"; 1381 | fragment_shader.innerHTML += " vec3 surface_normal;"; 1382 | fragment_shader.innerHTML += " if ( gl_FrontFacing ) {"; 1383 | fragment_shader.innerHTML += " surface_normal = normalize( vTransformedNormal );"; 1384 | fragment_shader.innerHTML += " }"; 1385 | fragment_shader.innerHTML += " else {"; 1386 | fragment_shader.innerHTML += " surface_normal = -normalize( vTransformedNormal );"; 1387 | fragment_shader.innerHTML += " }"; 1388 | fragment_shader.innerHTML += " if ( uNormalMap ) {"; 1389 | fragment_shader.innerHTML += " surface_normal = normalize( surface_normal - ( sin( dot( vDiffuseColor.rgb, vec3( 12.9898, 78.233, 1.0 ) ) ) ) );"; 1390 | fragment_shader.innerHTML += " }"; 1391 | fragment_shader.innerHTML += " vec3 diffuse = vDiffuseColor.rgb * uPointLightingColor * max( dot( surface_normal, light_direction ), 0.0 );"; 1392 | fragment_shader.innerHTML += " vec3 diffuse1 = vDiffuseColor.rgb * uPointLightingColor1 * max( dot( surface_normal, light_direction1 ), 0.0 );"; 1393 | fragment_shader.innerHTML += " vec3 specular = uPointLightingColor * pow( max( dot( half_vector, surface_normal ), 0.0 ), 100.0 );"; 1394 | fragment_shader.innerHTML += " vec3 specular1 = uPointLightingColor1 * pow( max( dot( half_vector1, surface_normal ), 0.0 ), 100.0 );"; 1395 | fragment_shader.innerHTML += " float light_outer_radius = 20.0;"; 1396 | fragment_shader.innerHTML += " float light_inner_radius = 0.0;"; 1397 | fragment_shader.innerHTML += " float light_outer_radius1 = 10.0;"; 1398 | fragment_shader.innerHTML += " float light_inner_radius1 = 0.0;"; 1399 | fragment_shader.innerHTML += " float light_distance = length( vPosition.xyz - uPointLightingLocation );"; 1400 | fragment_shader.innerHTML += " float light_distance1 = length( vPosition.xyz - uPointLightingLocation1 );"; 1401 | fragment_shader.innerHTML += " float attenuation = 1.0 - smoothstep( light_inner_radius, light_outer_radius, light_distance );"; 1402 | fragment_shader.innerHTML += " float attenuation1 = 1.0 - smoothstep( light_inner_radius1, light_outer_radius1, light_distance1 );"; 1403 | fragment_shader.innerHTML += " diffuse = attenuation * diffuse;"; 1404 | fragment_shader.innerHTML += " diffuse1 = attenuation1 * diffuse1;"; 1405 | fragment_shader.innerHTML += " specular = attenuation * specular;"; 1406 | fragment_shader.innerHTML += " specular1 = attenuation1 * specular1;"; 1407 | fragment_shader.innerHTML += " color = ambient + diffuse + diffuse1 + specular + specular1;"; 1408 | fragment_shader.innerHTML += " }"; 1409 | fragment_shader.innerHTML += " vec4 final_color;"; 1410 | fragment_shader.innerHTML += " if ( uAlphaBlendingEnabled ) {"; 1411 | fragment_shader.innerHTML += " final_color = vec4( color, vDiffuseColor.a );"; 1412 | fragment_shader.innerHTML += " }"; 1413 | fragment_shader.innerHTML += " else {"; 1414 | fragment_shader.innerHTML += " final_color = vec4( color, 1.0 );"; 1415 | fragment_shader.innerHTML += " }"; 1416 | fragment_shader.innerHTML += " float far = 50.0;"; 1417 | fragment_shader.innerHTML += " float fog_coord;"; 1418 | fragment_shader.innerHTML += " if ( uPerspectiveProjection ) {"; 1419 | fragment_shader.innerHTML += " fog_coord = ( gl_FragCoord.z / gl_FragCoord.w ) / far;"; 1420 | fragment_shader.innerHTML += " }"; 1421 | fragment_shader.innerHTML += " else {"; 1422 | fragment_shader.innerHTML += " fog_coord = ( gl_FragCoord.z / gl_FragCoord.w );"; 1423 | fragment_shader.innerHTML += " }"; 1424 | fragment_shader.innerHTML += " float fog_density = 1.5;"; 1425 | fragment_shader.innerHTML += " float fog = fog_coord * fog_density;"; 1426 | fragment_shader.innerHTML += " float fog_factor = clamp( 1.0 - fog, 0.0, 1.0 );"; 1427 | fragment_shader.innerHTML += " gl_FragColor = mix( fog_color, final_color, vec4( fog_factor, fog_factor, fog_factor, fog_factor ) );"; 1428 | fragment_shader.innerHTML += " gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / 2.2));"; 1429 | fragment_shader.innerHTML += " if ( uShowDepth ) {"; 1430 | fragment_shader.innerHTML += " gl_FragColor = mix( vec4( 1.0 ), vec4( vec3( 0.0 ), 1.0 ), smoothstep( 0.1, 1.0, fog_coord ) );"; 1431 | fragment_shader.innerHTML += " }"; 1432 | fragment_shader.innerHTML += " if ( uShowNormals ) {"; 1433 | fragment_shader.innerHTML += " vec3 nTN = normalize( vTransformedNormal );"; 1434 | fragment_shader.innerHTML += " gl_FragColor = vec4( nTN.r, nTN.g, nTN.b, 1.0 );"; 1435 | fragment_shader.innerHTML += " }"; 1436 | fragment_shader.innerHTML += " if ( uShowPosition ) {"; 1437 | fragment_shader.innerHTML += " vec3 nP = normalize( vPosition.xyz );"; 1438 | fragment_shader.innerHTML += " gl_FragColor = vec4( nP.r, nP.g, nP.b, 1.0 );"; 1439 | fragment_shader.innerHTML += " }"; 1440 | fragment_shader.innerHTML += "}"; 1441 | document.body.appendChild( fragment_shader ); 1442 | 1443 | initGL( canvas ); // Initialize WebGL. 1444 | initShaders( ); // Initialize the shaders. 1445 | initBuffers( ); // Initialize the 3D shapes. 1446 | initHUD( ); // Initialize the onscreen elements. 1447 | 1448 | gl.clearColor( base_color[ 0 ], base_color[ 1 ], base_color[ 2 ], 1.0 ); // Set the WebGL background color. 1449 | gl.enable( gl.DEPTH_TEST ); // Enable the depth buffer. 1450 | 1451 | window.requestAnimationFrame( drawScene ); // Begin rendering animation. 1452 | 1453 | } 1454 | 1455 | /* Taken from http://paulbourke.net/geometry/polygonise/ */ 1456 | 1457 | var marching_cubes_edge_table = [ 1458 | 1459 | 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 1460 | 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 1461 | 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 1462 | 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 1463 | 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 1464 | 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 1465 | 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 1466 | 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 1467 | 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 1468 | 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 1469 | 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 1470 | 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 1471 | 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 1472 | 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 1473 | 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 1474 | 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 1475 | 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 1476 | 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 1477 | 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 1478 | 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 1479 | 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 1480 | 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 1481 | 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 1482 | 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, 1483 | 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 1484 | 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, 1485 | 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 1486 | 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, 1487 | 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 1488 | 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, 1489 | 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 1490 | 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 1491 | 1492 | ]; 1493 | 1494 | var marching_cubes_triangle_table = [ 1495 | 1496 | [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1497 | [ 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1498 | [ 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1499 | [ 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1500 | [ 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1501 | [ 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1502 | [ 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1503 | [ 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 ], 1504 | [ 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1505 | [ 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1506 | [ 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1507 | [ 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 ], 1508 | [ 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1509 | [ 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 ], 1510 | [ 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 ], 1511 | [ 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1512 | [ 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1513 | [ 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1514 | [ 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1515 | [ 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 ], 1516 | [ 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1517 | [ 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 ], 1518 | [ 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 ], 1519 | [ 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 ], 1520 | [ 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1521 | [ 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 ], 1522 | [ 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 ], 1523 | [ 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 ], 1524 | [ 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 ], 1525 | [ 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 ], 1526 | [ 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 ], 1527 | [ 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 ], 1528 | [ 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1529 | [ 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1530 | [ 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1531 | [ 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 ], 1532 | [ 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1533 | [ 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 ], 1534 | [ 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 ], 1535 | [ 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 ], 1536 | [ 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1537 | [ 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 ], 1538 | [ 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 ], 1539 | [ 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 ], 1540 | [ 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 ], 1541 | [ 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 ], 1542 | [ 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 ], 1543 | [ 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 ], 1544 | [ 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1545 | [ 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 ], 1546 | [ 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 ], 1547 | [ 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1548 | [ 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 ], 1549 | [ 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 ], 1550 | [ 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 ], 1551 | [ 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 ], 1552 | [ 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 ], 1553 | [ 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 ], 1554 | [ 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 ], 1555 | [ 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 ], 1556 | [ 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 ], 1557 | [ 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 ], 1558 | [ 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 ], 1559 | [ 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1560 | [ 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1561 | [ 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1562 | [ 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1563 | [ 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 ], 1564 | [ 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1565 | [ 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 ], 1566 | [ 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 ], 1567 | [ 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 ], 1568 | [ 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1569 | [ 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 ], 1570 | [ 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 ], 1571 | [ 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 ], 1572 | [ 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 ], 1573 | [ 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 ], 1574 | [ 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 ], 1575 | [ 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 ], 1576 | [ 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1577 | [ 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 ], 1578 | [ 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 ], 1579 | [ 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 ], 1580 | [ 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 ], 1581 | [ 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 ], 1582 | [ 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 ], 1583 | [ 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 ], 1584 | [ 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 ], 1585 | [ 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 ], 1586 | [ 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 ], 1587 | [ 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 ], 1588 | [ 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 ], 1589 | [ 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 ], 1590 | [ 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 ], 1591 | [ 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 ], 1592 | [ 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1593 | [ 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 ], 1594 | [ 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 ], 1595 | [ 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 ], 1596 | [ 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 ], 1597 | [ 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 ], 1598 | [ 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1599 | [ 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 ], 1600 | [ 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 ], 1601 | [ 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 ], 1602 | [ 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 ], 1603 | [ 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 ], 1604 | [ 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 ], 1605 | [ 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 ], 1606 | [ 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 ], 1607 | [ 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1608 | [ 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 ], 1609 | [ 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 ], 1610 | [ 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 ], 1611 | [ 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 ], 1612 | [ 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 ], 1613 | [ 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 ], 1614 | [ 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 ], 1615 | [ 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1616 | [ 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 ], 1617 | [ 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 ], 1618 | [ 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 ], 1619 | [ 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 ], 1620 | [ 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 ], 1621 | [ 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1622 | [ 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 ], 1623 | [ 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1624 | [ 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1625 | [ 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1626 | [ 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1627 | [ 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 ], 1628 | [ 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1629 | [ 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 ], 1630 | [ 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 ], 1631 | [ 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 ], 1632 | [ 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1633 | [ 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 ], 1634 | [ 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 ], 1635 | [ 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 ], 1636 | [ 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 ], 1637 | [ 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 ], 1638 | [ 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 ], 1639 | [ 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 ], 1640 | [ 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1641 | [ 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 ], 1642 | [ 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 ], 1643 | [ 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 ], 1644 | [ 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 ], 1645 | [ 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 ], 1646 | [ 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 ], 1647 | [ 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 ], 1648 | [ 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 ], 1649 | [ 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1650 | [ 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 ], 1651 | [ 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 ], 1652 | [ 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 ], 1653 | [ 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 ], 1654 | [ 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 ], 1655 | [ 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1656 | [ 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1657 | [ 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 ], 1658 | [ 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 ], 1659 | [ 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 ], 1660 | [ 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 ], 1661 | [ 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 ], 1662 | [ 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 ], 1663 | [ 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 ], 1664 | [ 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 ], 1665 | [ 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 ], 1666 | [ 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 ], 1667 | [ 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 ], 1668 | [ 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 ], 1669 | [ 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 ], 1670 | [ 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 ], 1671 | [ 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 ], 1672 | [ 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 ], 1673 | [ 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 ], 1674 | [ 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 ], 1675 | [ 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 ], 1676 | [ 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 ], 1677 | [ 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 ], 1678 | [ 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 ], 1679 | [ 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 ], 1680 | [ 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 ], 1681 | [ 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 ], 1682 | [ 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 ], 1683 | [ 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1684 | [ 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 ], 1685 | [ 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 ], 1686 | [ 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1687 | [ 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1688 | [ 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1689 | [ 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 ], 1690 | [ 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 ], 1691 | [ 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 ], 1692 | [ 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 ], 1693 | [ 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 ], 1694 | [ 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 ], 1695 | [ 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 ], 1696 | [ 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 ], 1697 | [ 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 ], 1698 | [ 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 ], 1699 | [ 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 ], 1700 | [ 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1701 | [ 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 ], 1702 | [ 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 ], 1703 | [ 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1704 | [ 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 ], 1705 | [ 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 ], 1706 | [ 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 ], 1707 | [ 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 ], 1708 | [ 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 ], 1709 | [ 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 ], 1710 | [ 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 ], 1711 | [ 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1712 | [ 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 ], 1713 | [ 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 ], 1714 | [ 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 ], 1715 | [ 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 ], 1716 | [ 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 ], 1717 | [ 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1718 | [ 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 ], 1719 | [ 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1720 | [ 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 ], 1721 | [ 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 ], 1722 | [ 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 ], 1723 | [ 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 ], 1724 | [ 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 ], 1725 | [ 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 ], 1726 | [ 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 ], 1727 | [ 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 ], 1728 | [ 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 ], 1729 | [ 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 ], 1730 | [ 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 ], 1731 | [ 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1732 | [ 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 ], 1733 | [ 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 ], 1734 | [ 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1735 | [ 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1736 | [ 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1737 | [ 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 ], 1738 | [ 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 ], 1739 | [ 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1740 | [ 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 ], 1741 | [ 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 ], 1742 | [ 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1743 | [ 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1744 | [ 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 ], 1745 | [ 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1746 | [ 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 ], 1747 | [ 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1748 | [ 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1749 | [ 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1750 | [ 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1751 | [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ] 1752 | 1753 | ]; 1754 | -------------------------------------------------------------------------------- /source/assets/scripts/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2014 David Lettier 3 | lettier.com 4 | */ 5 | 6 | // The WebGL context. 7 | 8 | var gl; 9 | 10 | // The compiled and linked vertex and fragment shaders. 11 | 12 | var shaderProgram; 13 | 14 | // A stack for preserving matrix transformation states. 15 | 16 | var mvMatrixStack = [ ]; 17 | 18 | // Perspective or orthographic projection? 19 | 20 | var perspective_projection = true; 21 | 22 | // Model view and projection matrices. 23 | 24 | var mvMatrix = mat4.create( ); 25 | var pMatrix = mat4.create( ); 26 | 27 | // Isosurface data structures for holding the vertices, vertex normals, and vertex colors. 28 | 29 | var isosurfaceVertexPositionBuffer; 30 | var isosurfaceVertexNormalBuffer; 31 | var isosurfaceVertexColorBuffer; 32 | 33 | var isosurface1VertexPositionBuffer; 34 | var isosurface1VertexNormalBuffer; 35 | var isosurface1VertexColorBuffer; 36 | 37 | var pointLightSphereVertexPositionBuffer; 38 | var pointLightSphereVertexNormalBuffer; 39 | var pointLightSphereVertexColorBuffer; 40 | 41 | // Base color used for the ambient, fog, and clear-to colors. 42 | 43 | var base_color = [ 0.123, 0.154, 0.182 ]; 44 | 45 | // Lighting power. 46 | 47 | var lighting_power = 2; 48 | 49 | // Used for time based animation. 50 | 51 | var time_last = 0; 52 | 53 | // Used to rotate the isosurface. 54 | 55 | var rotation_radians = 0.0; 56 | var rotation_radians_step = 0.3; 57 | 58 | // Use lighting? 59 | 60 | var use_lighting = 1; 61 | 62 | // Use wireframe rendering? 63 | 64 | var use_wireframe = 0; 65 | 66 | // Render different buffers. 67 | 68 | var show_depth = 0; 69 | var show_normals = 0; 70 | var show_position = 0; 71 | 72 | // Alpha blending enabled? 73 | 74 | var alpha_blending_enabled = 0; 75 | 76 | // Normal map? 77 | 78 | var normal_map = 1; 79 | 80 | // Number of times initBuffers has been called. 81 | 82 | var init_buffers_called = 0; 83 | 84 | // Used to orbit the point lights. 85 | 86 | var point_light_theta = 1.57; 87 | var point_light_phi = 1.57; 88 | var point_light_theta_step = 0.39; 89 | var point_light_phi_step = 0.39; 90 | 91 | var point_light_theta1 = 1.57; 92 | var point_light_phi1 = 1.57; 93 | var point_light_theta_step1 = 0.3; 94 | var point_light_phi_step1 = 0.3; 95 | 96 | // Performs the draw loop iteration at roughly 60 frames per second. 97 | 98 | window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; 99 | 100 | // On-load event callback. 101 | 102 | window.onload = function ( ) { 103 | var gui = new dat.GUI(); 104 | 105 | gui.add(this, "lighting_power", 0, 5); 106 | gui.add(this, "perspective_projection", { On: true, Off: false }); 107 | gui.add(this, "use_lighting", { On: 1, Off: 0 }); 108 | gui.add(this, "use_wireframe", { On: 1, Off: 0 }); 109 | gui.add(this, "show_depth", { Yes: 1, No: 0 }); 110 | gui.add(this, "show_normals", { Yes: 1, No: 0 }); 111 | gui.add(this, "show_position", { Yes: 1, No: 0 }); 112 | gui.add(this, "normal_map", { On: 1, Off: 0 }); 113 | 114 | webGLStart( ); 115 | }; 116 | 117 | // Browser window re-size event callback. 118 | 119 | window.onresize = function ( ) { resize_contents( ); }; 120 | 121 | // Initializes the WebGL context. 122 | 123 | function initGL( canvas ) 124 | { 125 | 126 | try 127 | { 128 | 129 | gl = canvas.getContext( "webgl" ) || canvas.getContext( "experimental-webgl" ); 130 | 131 | gl.viewportWidth = canvas.width; 132 | gl.viewportHeight = canvas.height; 133 | 134 | } 135 | catch ( error ) 136 | { 137 | 138 | // Browser cannot initialize a WebGL context. 139 | 140 | window.location.assign( "http://get.webgl.org/" ); 141 | 142 | } 143 | 144 | if ( !gl ) 145 | { 146 | 147 | // Browser cannot initialize a WebGL context. 148 | 149 | window.location.assign( "http://get.webgl.org/" ); 150 | 151 | } 152 | 153 | } 154 | 155 | // Function to retrieve the shader strings thereby compiling them into shader programs run by the GPU. 156 | 157 | function getShader( gl, id ) 158 | { 159 | var shaderScript = document.getElementById( id ); 160 | 161 | if ( !shaderScript ) 162 | { 163 | 164 | console.error( "No shader scripts present." ); 165 | 166 | return null; 167 | 168 | } 169 | 170 | var str = ""; 171 | 172 | var k = shaderScript.firstChild; 173 | 174 | while ( k ) 175 | { 176 | 177 | if ( k.nodeType == 3 ) 178 | { 179 | 180 | str += k.textContent; 181 | 182 | } 183 | 184 | k = k.nextSibling; 185 | 186 | } 187 | 188 | var shader; 189 | 190 | if ( shaderScript.type == "x-shader/x-fragment" ) 191 | { 192 | 193 | shader = gl.createShader( gl.FRAGMENT_SHADER ); 194 | 195 | } 196 | else if ( shaderScript.type == "x-shader/x-vertex" ) 197 | { 198 | 199 | shader = gl.createShader( gl.VERTEX_SHADER ); 200 | 201 | } 202 | else 203 | { 204 | 205 | console.error( "No fragment/vertex shaders found." ); 206 | 207 | return null; 208 | 209 | } 210 | 211 | gl.shaderSource( shader, str ); 212 | 213 | gl.compileShader( shader ); 214 | 215 | if ( !gl.getShaderParameter( shader, gl.COMPILE_STATUS ) ) 216 | { 217 | 218 | console.error( gl.getShaderInfoLog( shader ) ); 219 | 220 | return null; 221 | 222 | } 223 | 224 | return shader; 225 | 226 | } 227 | 228 | // Initialize the vertex and fragment shaders. 229 | 230 | function initShaders( ) 231 | { 232 | 233 | var fragmentShader = getShader( gl, "shader-fs" ); 234 | var vertexShader = getShader( gl, "shader-vs" ); 235 | 236 | shaderProgram = gl.createProgram( ); 237 | 238 | gl.attachShader( shaderProgram, vertexShader ); 239 | gl.attachShader( shaderProgram, fragmentShader ); 240 | gl.linkProgram( shaderProgram ); 241 | 242 | if ( !gl.getProgramParameter( shaderProgram, gl.LINK_STATUS ) ) 243 | { 244 | 245 | console.error( "Could not initialize shaders." ); 246 | 247 | } 248 | 249 | gl.useProgram( shaderProgram ); 250 | 251 | // Acquire handles to shader program variables in order to pass data to the shaders. 252 | 253 | shaderProgram.vertexPositionAttribute = gl.getAttribLocation( shaderProgram, "aVertexPosition" ); 254 | gl.enableVertexAttribArray( shaderProgram.vertexPositionAttribute ); 255 | 256 | shaderProgram.vertexColorAttribute = gl.getAttribLocation( shaderProgram, "aVertexColor" ); 257 | gl.enableVertexAttribArray( shaderProgram.vertexColorAttribute ); 258 | 259 | shaderProgram.vertexNormalAttribute = gl.getAttribLocation( shaderProgram, "aVertexNormal" ); 260 | gl.enableVertexAttribArray( shaderProgram.vertexNormalAttribute ); 261 | 262 | shaderProgram.pMatrixUniform = gl.getUniformLocation( shaderProgram, "uPMatrix" ); 263 | shaderProgram.mvMatrixUniform = gl.getUniformLocation( shaderProgram, "uMVMatrix" ); 264 | shaderProgram.nMatrixUniform = gl.getUniformLocation( shaderProgram, "uNMatrix" ); 265 | 266 | shaderProgram.useLightingUniform = gl.getUniformLocation( shaderProgram, "uUseLighting" ); 267 | 268 | shaderProgram.alphaBlendingEnabled = gl.getUniformLocation( shaderProgram, "uAlphaBlendingEnabled" ); 269 | 270 | shaderProgram.normalMapEnabled = gl.getUniformLocation( shaderProgram, "uNormalMap" ); 271 | 272 | shaderProgram.perspectiveProjection = gl.getUniformLocation( shaderProgram, "uPerspectiveProjection" ); 273 | 274 | shaderProgram.showDepth = gl.getUniformLocation( shaderProgram, "uShowDepth" ); 275 | shaderProgram.showNormals = gl.getUniformLocation( shaderProgram, "uShowNormals" ); 276 | shaderProgram.showPosition = gl.getUniformLocation( shaderProgram, "uShowPosition" ); 277 | 278 | shaderProgram.ambientColorUniform = gl.getUniformLocation( shaderProgram, "uAmbientColor" ); 279 | 280 | shaderProgram.pointLightingLocationUniform = gl.getUniformLocation( shaderProgram, "uPointLightingLocation" ); 281 | shaderProgram.pointLightingColorUniform = gl.getUniformLocation( shaderProgram, "uPointLightingColor" ); 282 | 283 | shaderProgram.pointLightingLocationUniform1 = gl.getUniformLocation( shaderProgram, "uPointLightingLocation1" ); 284 | shaderProgram.pointLightingColorUniform1 = gl.getUniformLocation( shaderProgram, "uPointLightingColor1" ); 285 | 286 | } 287 | 288 | // Initialize all of the vertex, vertex normal, and vertex color buffers. 289 | 290 | function initBuffers( ) 291 | { 292 | 293 | // Generates one triangle complete with vertex normals and vertex colors. 294 | 295 | function triangle( p1, p2, p3, isosurface_function, resolution, invert_normals ) 296 | { 297 | 298 | // Push the vertices to this triangle face. 299 | // Pushing point 3, then 2, and then 1 so that the front face of the triangle 300 | // points outward from the surface. 301 | 302 | // Push point 1, then 2, and then 3 so that the front front face of the triangle 303 | // points inward from the surface. 304 | 305 | vertices.push( p3[ 0 ] ); vertices.push( p3[ 1 ] ); vertices.push( p3[ 2 ] ); 306 | vertices.push( p2[ 0 ] ); vertices.push( p2[ 1 ] ); vertices.push( p2[ 2 ] ); 307 | vertices.push( p1[ 0 ] ); vertices.push( p1[ 1 ] ); vertices.push( p1[ 2 ] ); 308 | 309 | // Calculate the isosurface gradient at point 1, 2, and 3 of the triangle. 310 | // These three gradient vectors are the vertex normals of this triangle. 311 | // This will provide a nice smooth appearance when the lighting is calculated. 312 | // These three gradient vectors will also be the vertex colors. 313 | 314 | var invert_normal = 1; 315 | 316 | if ( invert_normals === true ) invert_normal = -1; 317 | 318 | var vertext_color_alpha = 0.2; 319 | 320 | // Point 3. 321 | 322 | vertex_normal_x = 0.5 * ( isosurface_function( p3[ 0 ] + 1, p3[ 1 ], p3[ 2 ] ) - isosurface_function( p3[ 0 ] - 1, p3[ 1 ], p3[ 2 ] ) ) / resolution; 323 | vertex_normal_y = 0.5 * ( isosurface_function( p3[ 0 ], p3[ 1 ] + 1, p3[ 2 ] ) - isosurface_function( p3[ 0 ], p3[ 1 ] - 1, p3[ 2 ] ) ) / resolution; 324 | vertex_normal_z = 0.5 * ( isosurface_function( p3[ 0 ], p3[ 1 ], p3[ 2 ] + 1 ) - isosurface_function( p3[ 0 ], p3[ 1 ], p3[ 2 ] - 1 ) ) / resolution; 325 | 326 | vertex_normal_length = Math.sqrt( ( vertex_normal_x * vertex_normal_x ) + ( vertex_normal_y * vertex_normal_y ) + ( vertex_normal_z * vertex_normal_z ) ); 327 | 328 | if ( vertex_normal_length !== 0 ) 329 | { 330 | 331 | vertex_normal_x = vertex_normal_x / vertex_normal_length; 332 | vertex_normal_y = vertex_normal_y / vertex_normal_length; 333 | vertex_normal_z = vertex_normal_z / vertex_normal_length; 334 | 335 | } 336 | 337 | vertex_normals.push( invert_normal * vertex_normal_x ); vertex_normals.push( invert_normal * vertex_normal_y ); vertex_normals.push( invert_normal * vertex_normal_z ); 338 | 339 | // Push the vertex colors for this triangle face point. 340 | 341 | vertex_colors.push( 1.0 - vertex_normal_x ); vertex_colors.push( 1.0 - vertex_normal_y ); vertex_colors.push( 1.0 - vertex_normal_z ); vertex_colors.push( vertext_color_alpha ); 342 | 343 | // Point 2. 344 | 345 | vertex_normal_x = 0.5 * ( isosurface_function( p2[ 0 ] + 1, p2[ 1 ], p2[ 2 ] ) - isosurface_function( p2[ 0 ] - 1, p2[ 1 ], p2[ 2 ] ) ) / resolution; 346 | vertex_normal_y = 0.5 * ( isosurface_function( p2[ 0 ], p2[ 1 ] + 1, p2[ 2 ] ) - isosurface_function( p2[ 0 ], p2[ 1 ] - 1, p2[ 2 ] ) ) / resolution; 347 | vertex_normal_z = 0.5 * ( isosurface_function( p2[ 0 ], p2[ 1 ], p2[ 2 ] + 1 ) - isosurface_function( p2[ 0 ], p2[ 1 ], p2[ 2 ] - 1 ) ) / resolution; 348 | 349 | vertex_normal_length = Math.sqrt( ( vertex_normal_x * vertex_normal_x ) + ( vertex_normal_y * vertex_normal_y ) + ( vertex_normal_z * vertex_normal_z ) ); 350 | 351 | if ( vertex_normal_length !== 0 ) 352 | { 353 | 354 | vertex_normal_x = vertex_normal_x / vertex_normal_length; 355 | vertex_normal_y = vertex_normal_y / vertex_normal_length; 356 | vertex_normal_z = vertex_normal_z / vertex_normal_length; 357 | 358 | } 359 | 360 | vertex_normals.push( invert_normal * vertex_normal_x ); vertex_normals.push( invert_normal * vertex_normal_y ); vertex_normals.push( invert_normal * vertex_normal_z ); 361 | 362 | // Push the vertex colors for this triangle face point. 363 | 364 | vertex_colors.push( 1.0 - vertex_normal_x ); vertex_colors.push( 1.0 - vertex_normal_y ); vertex_colors.push( 1.0 - vertex_normal_z ); vertex_colors.push( vertext_color_alpha ); 365 | 366 | // Point 1. 367 | 368 | var vertex_normal_x = 0.5 * ( isosurface_function( p1[ 0 ] + 1, p1[ 1 ], p1[ 2 ] ) - isosurface_function( p1[ 0 ] - 1, p1[ 1 ], p1[ 2 ] ) ) / resolution; 369 | var vertex_normal_y = 0.5 * ( isosurface_function( p1[ 0 ], p1[ 1 ] + 1, p1[ 2 ] ) - isosurface_function( p1[ 0 ], p1[ 1 ] - 1, p1[ 2 ] ) ) / resolution; 370 | var vertex_normal_z = 0.5 * ( isosurface_function( p1[ 0 ], p1[ 1 ], p1[ 2 ] + 1 ) - isosurface_function( p1[ 0 ], p1[ 1 ], p1[ 2 ] - 1 ) ) / resolution; 371 | 372 | // Normalize. 373 | 374 | var vertex_normal_length = Math.sqrt( ( vertex_normal_x * vertex_normal_x ) + ( vertex_normal_y * vertex_normal_y ) + ( vertex_normal_z * vertex_normal_z ) ); 375 | 376 | if ( vertex_normal_length !== 0 ) 377 | { 378 | 379 | vertex_normal_x = vertex_normal_x / vertex_normal_length; 380 | vertex_normal_y = vertex_normal_y / vertex_normal_length; 381 | vertex_normal_z = vertex_normal_z / vertex_normal_length; 382 | 383 | } 384 | 385 | vertex_normals.push( invert_normal * vertex_normal_x ); vertex_normals.push( invert_normal * vertex_normal_y ); vertex_normals.push( invert_normal * vertex_normal_z ); 386 | 387 | // Push the vertex colors for this triangle face point. 388 | 389 | vertex_colors.push( 1.0 - vertex_normal_x ); vertex_colors.push( 1.0 - vertex_normal_y ); vertex_colors.push( 1.0 - vertex_normal_z ); vertex_colors.push( vertext_color_alpha ); 390 | 391 | } 392 | 393 | // The marching cubes algorithm. 394 | 395 | function marching_cubes( grid_min, grid_max, resolution, iso_level, isosurface_function, invert_normals ) 396 | { 397 | 398 | // Cube grid dimensions. 399 | 400 | var cube_grid_axis_min = grid_min; 401 | var cube_grid_axis_max = grid_max; 402 | 403 | // Generate the cube grid scalar field. 404 | 405 | /* 406 | 407 | j 408 | | 409 | | k 410 | | . 411 | | . 412 | | . 413 | | . 414 | | . 415 | |._________________i 416 | 417 | */ 418 | 419 | function Scalar_Point( x, y, z, value ) 420 | { 421 | 422 | this.id = x.toFixed( 2 ) + y.toFixed( 2 ) + z.toFixed( 2 ); 423 | 424 | this.x = x; 425 | this.y = y; 426 | this.z = z; 427 | this.value = value; 428 | 429 | } 430 | 431 | var scalar_points = { }; 432 | 433 | for ( var k = cube_grid_axis_min; k <= ( cube_grid_axis_max + resolution ); k += resolution ) 434 | { 435 | 436 | for ( var j = cube_grid_axis_min; j <= ( cube_grid_axis_max + resolution ); j += resolution ) 437 | { 438 | 439 | for ( var i = cube_grid_axis_min; i <= ( cube_grid_axis_max + resolution ); i += resolution ) 440 | { 441 | 442 | var x = i; 443 | var y = j; 444 | var z = k; 445 | 446 | var value = isosurface_function( x, y, z ); 447 | 448 | var scalar_point = new Scalar_Point( x, y, z, value ); 449 | 450 | scalar_points[ scalar_point.id ] = scalar_point; 451 | 452 | } 453 | 454 | } 455 | 456 | } 457 | 458 | function edge_intersection_interpolation( cube_va, cube_vb ) 459 | { 460 | 461 | if ( Math.abs( iso_level - cube_va.value ) < 0.00001 ) return [ cube_va.x, cube_va.y, cube_va.z ]; 462 | 463 | if ( Math.abs( iso_level - cube_vb.value ) < 0.00001 ) return [ cube_vb.x, cube_vb.y, cube_vb.z ]; 464 | 465 | if ( Math.abs( cube_va.value - cube_vb.value ) < 0.00001 ) return [ cube_va.x, cube_va.y, cube_va.z ]; 466 | 467 | var mean = ( iso_level - cube_va.value ) / ( cube_vb.value - cube_va.value ); 468 | 469 | var point = [ ]; 470 | 471 | point.push( cube_va.x + mean * ( cube_vb.x - cube_va.x ) ); 472 | point.push( cube_va.y + mean * ( cube_vb.y - cube_va.y ) ); 473 | point.push( cube_va.z + mean * ( cube_vb.z - cube_va.z ) ); 474 | 475 | return point; 476 | } 477 | 478 | for ( var k = cube_grid_axis_min; k < cube_grid_axis_max; k += resolution ) 479 | { 480 | 481 | for ( var j = cube_grid_axis_min; j < cube_grid_axis_max; j += resolution ) 482 | { 483 | 484 | for ( var i = cube_grid_axis_min; i < cube_grid_axis_max; i += resolution ) 485 | { 486 | 487 | // Perform the algorithm on one cube in the grid. 488 | 489 | // The cube's vertices. 490 | // There are eight of them. 491 | 492 | // 4---------5 493 | // /| /| 494 | // / | / | 495 | // 7---------6 | 496 | // | | | | 497 | // | 0------|--1 498 | // | / | / 499 | // |/ |/ 500 | // 3---------2 501 | 502 | var cube_v3 = scalar_points[ i.toFixed( 2 ) + j.toFixed( 2 ) + k.toFixed( 2 ) ]; // Lower left front corner. 503 | var cube_v2 = scalar_points[ ( i + resolution ).toFixed( 2 ) + j.toFixed( 2 ) + k.toFixed( 2 ) ]; // Lower right front corner. 504 | var cube_v6 = scalar_points[ ( i + resolution ).toFixed( 2 ) + ( j + resolution ).toFixed( 2 ) + k.toFixed( 2 ) ]; // Upper right front corner. 505 | var cube_v7 = scalar_points[ i.toFixed( 2 ) + ( j + resolution ).toFixed( 2 ) + k.toFixed( 2 ) ]; // Upper left front corner 506 | 507 | var cube_v0 = scalar_points[ i.toFixed( 2 ) + j.toFixed( 2 ) + ( k + resolution ).toFixed( 2 ) ]; // Lower left back corner. 508 | var cube_v1 = scalar_points[ ( i + resolution ).toFixed( 2 ) + j.toFixed( 2 ) + ( k + resolution ).toFixed( 2 ) ]; // Lower right back corner. 509 | var cube_v5 = scalar_points[ ( i + resolution ).toFixed( 2 ) + ( j + resolution ).toFixed( 2 ) + ( k + resolution ).toFixed( 2 ) ]; // Upper right back corner. 510 | var cube_v4 = scalar_points[ i.toFixed( 2 ) + ( j + resolution ).toFixed( 2 ) + ( k + resolution ).toFixed( 2 ) ]; // Upper left back corner. 511 | 512 | var cube_index = 0; 513 | 514 | if ( cube_v0.value < iso_level ) cube_index |= 1; 515 | if ( cube_v1.value < iso_level ) cube_index |= 2; 516 | if ( cube_v2.value < iso_level ) cube_index |= 4; 517 | if ( cube_v3.value < iso_level ) cube_index |= 8; 518 | if ( cube_v4.value < iso_level ) cube_index |= 16; 519 | if ( cube_v5.value < iso_level ) cube_index |= 32; 520 | if ( cube_v6.value < iso_level ) cube_index |= 64; 521 | if ( cube_v7.value < iso_level ) cube_index |= 128; 522 | 523 | // Does the isosurface not intersect any edges of the cube? 524 | 525 | if ( marching_cubes_edge_table[ cube_index ] === 0 ) continue; 526 | 527 | // What edges of the cube does the isosurface intersect? 528 | // For each cube edge intersected, interpolate an intersection vertex between the edge's incident vertices. 529 | // These vertices of intersection will form the triangle(s) that approximate the isosurface. 530 | 531 | // There are 12 edges in a cube. 532 | 533 | // 4----5----5 534 | // 8 /| 6/| 535 | // / |9 / | 10 536 | // 7----7----6 | 537 | // | | | | 538 | // 12 | 0---1--|--1 539 | // | / | / 540 | // |/ 4 11 |/ 2 541 | // 3----3----2 542 | // 543 | // 1={0,1}, 2={1,2}, 3={2,3}, 4={3,0}, 544 | // 5={4,5}, 6={5,6}, 7={6,7}, 8={7,4}, 545 | // 9={0,4}, 10={5,1}, 11={2,6}, 12={3,7} 546 | 547 | // Base ten slot: 2048 | 1024 | 512 | 256 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 548 | // Base two slot: 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 549 | // Edge slot: 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 550 | 551 | var vertices_of_intersection = [ ]; 552 | 553 | // Fill allocate the array. 554 | 555 | for ( var c = 0; c < 12; ++c ) 556 | { 557 | 558 | vertices_of_intersection.push( [ 0, 0, 0 ] ); 559 | 560 | } 561 | 562 | if ( marching_cubes_edge_table[ cube_index ] & 1 ) // Intersects edge one. 563 | { 564 | 565 | vertices_of_intersection[ 0 ] = edge_intersection_interpolation( cube_v0, cube_v1 ); 566 | 567 | } 568 | 569 | if ( marching_cubes_edge_table[ cube_index ] & 2 ) // Intersects edge two. 570 | { 571 | 572 | vertices_of_intersection[ 1 ] = edge_intersection_interpolation( cube_v1, cube_v2 ); 573 | 574 | } 575 | 576 | if ( marching_cubes_edge_table[ cube_index ] & 4 ) // Intersects edge three. 577 | { 578 | 579 | vertices_of_intersection[ 2 ] = edge_intersection_interpolation( cube_v2, cube_v3 ); 580 | 581 | } 582 | 583 | if ( marching_cubes_edge_table[ cube_index ] & 8 ) // Intersects edge four. 584 | { 585 | 586 | vertices_of_intersection[ 3 ] = edge_intersection_interpolation( cube_v3, cube_v0 ); 587 | 588 | } 589 | 590 | if ( marching_cubes_edge_table[ cube_index ] & 16 ) // Intersects edge five. 591 | { 592 | 593 | vertices_of_intersection[ 4 ] = edge_intersection_interpolation( cube_v4, cube_v5 ); 594 | 595 | } 596 | 597 | if ( marching_cubes_edge_table[ cube_index ] & 32 ) // Intersects edge six. 598 | { 599 | 600 | vertices_of_intersection[ 5 ] = edge_intersection_interpolation( cube_v5, cube_v6 ); 601 | 602 | } 603 | 604 | if ( marching_cubes_edge_table[ cube_index ] & 64 ) // Intersects edge seven. 605 | { 606 | 607 | vertices_of_intersection[ 6 ] = edge_intersection_interpolation( cube_v6, cube_v7 ); 608 | 609 | } 610 | 611 | if ( marching_cubes_edge_table[ cube_index ] & 128 ) // Intersects edge eight. 612 | { 613 | 614 | vertices_of_intersection[ 7 ] = edge_intersection_interpolation( cube_v7, cube_v4 ); 615 | 616 | } 617 | 618 | if ( marching_cubes_edge_table[ cube_index ] & 256 ) // Intersects edge nine. 619 | { 620 | 621 | vertices_of_intersection[ 8 ] = edge_intersection_interpolation( cube_v0, cube_v4 ); 622 | 623 | } 624 | 625 | if ( marching_cubes_edge_table[ cube_index ] & 512 ) // Intersects edge ten. 626 | { 627 | 628 | vertices_of_intersection[ 9 ] = edge_intersection_interpolation( cube_v1, cube_v5 ); 629 | 630 | } 631 | 632 | if ( marching_cubes_edge_table[ cube_index ] & 1024 ) // Intersects edge eleven. 633 | { 634 | 635 | vertices_of_intersection[ 10 ] = edge_intersection_interpolation( cube_v2, cube_v6 ); 636 | 637 | } 638 | 639 | if ( marching_cubes_edge_table[ cube_index ] & 2048 ) // Intersects edge twelve. 640 | { 641 | 642 | vertices_of_intersection[ 11 ] = edge_intersection_interpolation( cube_v3, cube_v7 ); 643 | 644 | } 645 | 646 | // Create the triangles. 647 | // Three vertices make up a triangle per iteration. 648 | 649 | for ( var a = 0; marching_cubes_triangle_table[ cube_index ][ a ] != -1; a = a + 3 ) 650 | { 651 | 652 | var v1 = vertices_of_intersection[ marching_cubes_triangle_table[ cube_index ][ a ] ]; 653 | var v2 = vertices_of_intersection[ marching_cubes_triangle_table[ cube_index ][ a + 1 ] ]; 654 | var v3 = vertices_of_intersection[ marching_cubes_triangle_table[ cube_index ][ a + 2 ] ]; 655 | 656 | triangle( v1, v2, v3, isosurface_function, resolution, invert_normals ); 657 | 658 | } 659 | 660 | } 661 | 662 | } 663 | 664 | } 665 | 666 | } 667 | 668 | // Begin creating the isosurfaces. 669 | 670 | // First isosurface. 671 | 672 | // Temporary arrays to hold all of the data that will be read into the buffers. 673 | 674 | var vertices = [ ]; 675 | var vertex_normals = [ ]; 676 | var vertex_colors = [ ]; 677 | 678 | function isosurface_function( x, y, z ) 679 | { 680 | 681 | // Goursat's surface. 682 | 683 | var x2 = x * x; 684 | var y2 = y * y; 685 | var z2 = z * z; 686 | 687 | var x4 = x2 * x2; 688 | var y4 = y2 * y2; 689 | var z4 = z2 * z2; 690 | 691 | var a = -1.0; 692 | var b = 0.0; 693 | var c = 0.5; 694 | 695 | var d = x2 + y2 + z2; 696 | var d2 = d * d; 697 | 698 | var value = x4 + y4 + z4 + a * d2 + b * d + c; 699 | 700 | return value; 701 | 702 | } 703 | 704 | // Grid min, grid max, resolution, iso-level, isosurface function, and invert normals. 705 | // Do not set the resolution to small. 706 | 707 | marching_cubes( -1.0, 1.0, 0.07, 0, isosurface_function, false ); 708 | 709 | // Create the vertex buffer and bind it getting it ready to read in the vertices to the isosurface. 710 | 711 | isosurfaceVertexPositionBuffer = gl.createBuffer( ); 712 | 713 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexPositionBuffer ); 714 | 715 | // Bind and fill the isosurface vertices. 716 | 717 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertices ), gl.STATIC_DRAW ); 718 | isosurfaceVertexPositionBuffer.itemSize = 3; 719 | isosurfaceVertexPositionBuffer.numItems = vertices.length / 3; 720 | 721 | // Bind and fill the isosurface vertex normals. 722 | 723 | isosurfaceVertexNormalBuffer = gl.createBuffer( ); 724 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexNormalBuffer ); 725 | 726 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_normals ), gl.STATIC_DRAW ); 727 | isosurfaceVertexNormalBuffer.itemSize = 3; 728 | isosurfaceVertexNormalBuffer.numItems = vertex_normals.length / 3; 729 | 730 | // Bind and fill the isosurface vertex colors. 731 | 732 | isosurfaceVertexColorBuffer = gl.createBuffer( ); 733 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexColorBuffer ); 734 | 735 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_colors ), gl.STATIC_DRAW ); 736 | isosurfaceVertexColorBuffer.itemSize = 4; 737 | isosurfaceVertexColorBuffer.numItems = vertex_colors.length / 4; 738 | 739 | // Second isosurface. 740 | 741 | if ( init_buffers_called === 0 ) 742 | { 743 | 744 | vertices = [ ]; 745 | vertex_normals = [ ]; 746 | vertex_colors = [ ]; 747 | 748 | function isosurface_function1( x, y, z ) 749 | { 750 | 751 | // The Taubin (heart) surface. 752 | 753 | // Swapped y and z from the standard formula. 754 | 755 | var x2 = x * x; 756 | var z2 = z * z; 757 | var y2 = y * y; 758 | var y3 = y * y * y; 759 | 760 | var a = x2 + ( 9 / 4 ) * z2 + y2 - 1; 761 | var a3 = a * a * a; 762 | 763 | var value = a3 - ( x2 * y3 ) - ( ( 9 / 80 ) * z2 * y3 ); 764 | 765 | return value; 766 | 767 | } 768 | 769 | // Grid min, grid max, resolution, iso-level, isosurface function, and invert normals. 770 | // Do not set the resolution to small. 771 | 772 | marching_cubes( -1.5, 1.5, 0.08, 0, isosurface_function1, false ); 773 | 774 | // Create the vertex buffer and bind it getting it ready to read in the vertices to the isosurface. 775 | 776 | isosurface1VertexPositionBuffer = gl.createBuffer( ); 777 | 778 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexPositionBuffer ); 779 | 780 | // Bind and fill the isosurface vertices. 781 | 782 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertices ), gl.STATIC_DRAW ); 783 | isosurface1VertexPositionBuffer.itemSize = 3; 784 | isosurface1VertexPositionBuffer.numItems = vertices.length / 3; 785 | 786 | // Bind and fill the isosurface vertex normals. 787 | 788 | isosurface1VertexNormalBuffer = gl.createBuffer( ); 789 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexNormalBuffer ); 790 | 791 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_normals ), gl.STATIC_DRAW ); 792 | isosurface1VertexNormalBuffer.itemSize = 3; 793 | isosurface1VertexNormalBuffer.numItems = vertex_normals.length / 3; 794 | 795 | // Bind and fill the isosurface vertex colors. 796 | 797 | isosurface1VertexColorBuffer = gl.createBuffer( ); 798 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexColorBuffer ); 799 | 800 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_colors ), gl.STATIC_DRAW ); 801 | isosurface1VertexColorBuffer.itemSize = 4; 802 | isosurface1VertexColorBuffer.numItems = vertex_colors.length / 4; 803 | 804 | } 805 | 806 | // Point light representation. 807 | 808 | if ( init_buffers_called === 0 ) // Do not recreate the point light sphere more than once. 809 | { 810 | 811 | vertices = [ ]; 812 | vertex_normals = [ ]; 813 | vertex_colors = [ ]; 814 | 815 | function isosurface_function2( x, y, z ) 816 | { 817 | 818 | // A sphere. 819 | 820 | var value = ( ( x - 0 ) * ( x - 0 ) ) + 821 | ( ( y - 0 ) * ( y - 0 ) ) + 822 | ( ( z - 0 ) * ( z - 0 ) ) - 823 | ( ( 0.5 ) * ( 0.5 ) ); 824 | 825 | return value; 826 | 827 | } 828 | 829 | // Grid min, grid max, resolution, iso-level, isosurface function, and invert normals. 830 | // Do not set the resolution to small. 831 | 832 | marching_cubes( -2, 2, 0.2, 0, isosurface_function2, false ); 833 | 834 | // Make the sphere bright white. 835 | 836 | for ( var i = 0; i < vertex_colors.length; i += 4 ) 837 | { 838 | 839 | vertex_colors[ i ] = 200.0; 840 | vertex_colors[ i + 1 ] = 200.0; 841 | vertex_colors[ i + 2 ] = 200.0; 842 | vertex_colors[ i + 3 ] = 1.0; 843 | 844 | } 845 | 846 | // Create the vertex buffer and bind it getting it ready to read in the vertices to the isosurface. 847 | 848 | pointLightSphereVertexPositionBuffer = gl.createBuffer( ); 849 | 850 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexPositionBuffer ); 851 | 852 | // Bind and fill the isosurface vertices. 853 | 854 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertices ), gl.STATIC_DRAW ); 855 | pointLightSphereVertexPositionBuffer.itemSize = 3; 856 | pointLightSphereVertexPositionBuffer.numItems = vertices.length / 3; 857 | 858 | // Bind and fill the isosurface vertex normals. 859 | 860 | pointLightSphereVertexNormalBuffer = gl.createBuffer( ); 861 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexNormalBuffer ); 862 | 863 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_normals ), gl.STATIC_DRAW ); 864 | pointLightSphereVertexNormalBuffer.itemSize = 3; 865 | pointLightSphereVertexNormalBuffer.numItems = vertex_normals.length / 3; 866 | 867 | // Bind and fill the isosurface vertex colors. 868 | 869 | pointLightSphereVertexColorBuffer = gl.createBuffer( ); 870 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexColorBuffer ); 871 | 872 | gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_colors ), gl.STATIC_DRAW ); 873 | pointLightSphereVertexColorBuffer.itemSize = 4; 874 | pointLightSphereVertexColorBuffer.numItems = vertex_colors.length / 4; 875 | 876 | } 877 | 878 | init_buffers_called += 1; 879 | 880 | } 881 | 882 | function initHUD( ) 883 | { 884 | 885 | // Create and show an onscreen logo. 886 | 887 | var logo_box = document.createElement( "div" ); 888 | logo_box.id = "logo_box"; 889 | logo_box.title = "Lettier"; 890 | logo_box.className = "logo_box"; 891 | logo_box.innerHTML = ""; 892 | 893 | document.body.appendChild( logo_box ); 894 | 895 | var logo_image = document.getElementById( "logo" ); 896 | logo_image_height = logo_image.clientHeight * 0.5; 897 | logo_image_width = logo_image.clientWidth * 0.5; 898 | logo_image.style.height = logo_image_height + "px"; 899 | logo_image.style.width = logo_image_width + "px"; 900 | logo_box.style.top = window.innerHeight - logo_image_height - 10 + "px"; 901 | logo_box.style.left = window.innerWidth - logo_image_width - 10 + "px"; 902 | 903 | } 904 | 905 | // Pass to the vertex shader the needed matrices. 906 | 907 | function setMatrixUniforms( ) 908 | { 909 | 910 | // Pass the vertex shader the projection matrix and the model-view matrix. 911 | 912 | gl.uniformMatrix4fv( shaderProgram.pMatrixUniform, false, pMatrix ); 913 | gl.uniformMatrix4fv( shaderProgram.mvMatrixUniform, false, mvMatrix ); 914 | 915 | // Pass the vertex normal matrix to the shader so it can compute the lighting calculations. 916 | 917 | var normalMatrix = mat3.create( ); 918 | mat3.normalFromMat4( normalMatrix, mvMatrix ); 919 | gl.uniformMatrix3fv( shaderProgram.nMatrixUniform, false, normalMatrix ); 920 | 921 | } 922 | 923 | function mvPushMatrix( ) 924 | { 925 | 926 | // Save the model view matrix for later use. 927 | 928 | var copy = mat4.create( ); 929 | copy = mat4.copy( copy, mvMatrix ); 930 | mvMatrixStack.push( copy ); 931 | 932 | } 933 | 934 | function mvPopMatrix( ) 935 | { 936 | 937 | // Gather the previously pushed model view matrix. 938 | 939 | if ( mvMatrixStack.length === 0 ) 940 | { 941 | 942 | console.error( "mvMatrixStack empty." ); 943 | 944 | } 945 | 946 | mvMatrix = mvMatrixStack.pop( ); 947 | } 948 | 949 | // The function renders the isosurfaces lit with the point light. 950 | // It also animates the rotation of the isosurfaces. 951 | 952 | function drawScene( timestamp ) 953 | { 954 | 955 | // Call this function to draw the next frame. 956 | 957 | window.requestAnimationFrame( drawScene ); 958 | 959 | // Time based animation instead of frame based animation. 960 | 961 | var time_now = new Date( ).getTime( ); 962 | 963 | if ( time_last !== 0 ) 964 | { 965 | 966 | var time_delta = ( time_now - time_last ) / 1000.0; 967 | 968 | rotation_radians += rotation_radians_step * time_delta; 969 | 970 | if ( rotation_radians > ( Math.PI * 2 ) ) rotation_radians = 0.0; 971 | 972 | if ( Number(use_lighting) === 1 ) 973 | { 974 | 975 | point_light_theta += point_light_theta_step * time_delta; 976 | point_light_phi += point_light_phi_step * time_delta; 977 | 978 | if ( point_light_theta > ( Math.PI * 2 ) ) point_light_theta = 0.0; 979 | if ( point_light_phi > ( Math.PI * 2 ) ) point_light_phi = 0.0; 980 | 981 | point_light_theta1 += point_light_theta_step1 * time_delta; 982 | point_light_phi1 += point_light_phi_step1 * time_delta; 983 | 984 | if ( point_light_theta1 > ( Math.PI * 2 ) ) point_light_theta1 = 0.0; 985 | if ( point_light_phi1 > ( Math.PI * 2 ) ) point_light_phi1 = 0.0; 986 | 987 | } 988 | 989 | } 990 | 991 | time_last = time_now; 992 | 993 | // Set the size of and clear the render window. 994 | 995 | gl.viewport( 0, 0, gl.viewportWidth, gl.viewportHeight ); 996 | 997 | gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT ); 998 | 999 | // Create the projection matrix. 1000 | 1001 | var near = 0.1; 1002 | var far = 50.0; 1003 | var fov_d = 55.0; 1004 | var fov_r = 55 * ( Math.PI / 180.0 ); 1005 | 1006 | if ( JSON.parse(perspective_projection) ) 1007 | { 1008 | 1009 | // Resulting perspective matrix, FOV in radians, aspect ratio, near, and far clipping plane. 1010 | 1011 | mat4.perspective( pMatrix, fov_r, gl.viewportWidth / gl.viewportHeight, near, far ); 1012 | 1013 | // Let the fragment shader know that perspective projection is being used. 1014 | 1015 | gl.uniform1i( shaderProgram.perspectiveProjection, 1 ); 1016 | 1017 | } 1018 | else 1019 | { 1020 | 1021 | // The goal is to have the object be about the same size in the window 1022 | // during orthographic project as it is during perspective projection. 1023 | 1024 | var a = gl.viewportWidth / gl.viewportHeight; // Window aspect ratio. 1025 | var h = 2 * ( 25 * Math.tan( fov_r / 2 ) ); // 25 is the absolute distance from the world origin to all of the isosurfaces' local origins. 1026 | var w = h * a; // Knowing the new window height size, get the new window width size based on the aspect ratio. 1027 | 1028 | // The canvas' origin is the upper left corner. To the right is the positive x-axis. 1029 | // Going down is the positive y-axis. 1030 | 1031 | // Any object at the world origin would appear at the upper left hand corner. 1032 | // Shift the origin to the middle of the screen. 1033 | 1034 | // Also, invert the y-axis as WebgL's positive y-axis points up while the canvas' positive 1035 | // y-axis points down the screen. 1036 | 1037 | // (0,O)------------------------(w,0) 1038 | // | | 1039 | // | | 1040 | // | | 1041 | // (0,h)------------------------(w,h) 1042 | // 1043 | // (-(w/2),(h/2))------------------------((w/2),(h/2)) 1044 | // | | 1045 | // | (0,0) | 1046 | // | | 1047 | // (-(w/2),-(h/2))------------------------((w/2),-(h/2)) 1048 | 1049 | // Resulting perspective matrix, left, right, bottom, top, near, and far clipping plane. 1050 | 1051 | mat4.ortho( 1052 | 1053 | pMatrix, 1054 | -( w / 2 ), 1055 | ( w / 2 ), 1056 | -( h / 2 ), 1057 | ( h / 2 ), 1058 | near, 1059 | far 1060 | 1061 | ); 1062 | 1063 | // Let the fragment shader know that orthographic projection is being used. 1064 | 1065 | gl.uniform1i( shaderProgram.perspectiveProjection, 0 ); 1066 | 1067 | } 1068 | 1069 | // Render different buffers to screen. 1070 | 1071 | gl.uniform1i( shaderProgram.showDepth, show_depth ); 1072 | gl.uniform1i( shaderProgram.showNormals, show_normals ); 1073 | gl.uniform1i( shaderProgram.showPosition, show_position ); 1074 | 1075 | // Move to the 3D space origin. 1076 | 1077 | mat4.identity( mvMatrix ); 1078 | 1079 | // Disable alpha blending. 1080 | 1081 | gl.disable( gl.BLEND ); 1082 | 1083 | alpha_blending_enabled = 0; 1084 | 1085 | gl.uniform1i( shaderProgram.alphaBlendingEnabled, alpha_blending_enabled ); 1086 | 1087 | if ( Number(use_lighting) === 1 ) 1088 | { 1089 | 1090 | // Pass the lighting parameters to the fragment shader. 1091 | 1092 | // Global ambient color. 1093 | 1094 | gl.uniform3f( shaderProgram.ambientColorUniform, base_color[ 0 ], base_color[ 1 ], base_color[ 2 ] ); 1095 | 1096 | // Point light 1. 1097 | 1098 | var point_light_position_x = 0 + 13.5 * Math.cos( point_light_theta ) * Math.sin( point_light_phi ); 1099 | var point_light_position_y = 0 + 13.5 * Math.sin( point_light_theta ) * Math.sin( point_light_phi ); 1100 | var point_light_position_z = -25 + 13.5 * Math.cos( point_light_phi ); 1101 | 1102 | gl.uniform3f( shaderProgram.pointLightingColorUniform, lighting_power, lighting_power, lighting_power ); 1103 | 1104 | gl.uniform3f( shaderProgram.pointLightingLocationUniform, point_light_position_x, point_light_position_y, point_light_position_z ); 1105 | 1106 | // Point light 2. 1107 | 1108 | var point_light_position_x1 = 0 + 8.0 * Math.cos( point_light_theta1 ) * Math.sin( point_light_phi1 ); 1109 | var point_light_position_y1 = 0 + 8.0 * Math.sin( point_light_theta1 ) * Math.sin( point_light_phi1 ); 1110 | var point_light_position_z1 = -25 + 8.0 * Math.cos( point_light_phi1 ); 1111 | 1112 | gl.uniform3f( shaderProgram.ambientColorUniform1, base_color[ 0 ], base_color[ 1 ], base_color[ 2 ] ); 1113 | 1114 | gl.uniform3f( shaderProgram.pointLightingColorUniform1, lighting_power, lighting_power, lighting_power ); 1115 | 1116 | gl.uniform3f( shaderProgram.pointLightingLocationUniform1, point_light_position_x1, point_light_position_y1, point_light_position_z1 ); 1117 | 1118 | // Turn off lighting for a moment so that the point light isosurface is 1119 | // bright simulating that the light is emanating from the surface. 1120 | 1121 | use_lighting = 0; 1122 | 1123 | gl.uniform1i( shaderProgram.useLightingUniform, use_lighting ); 1124 | 1125 | // Point light surfaces. 1126 | 1127 | // Save the model view matrix state. 1128 | 1129 | mvPushMatrix( ); 1130 | 1131 | // Point light surface 1. 1132 | 1133 | mat4.translate( mvMatrix, mvMatrix, [ point_light_position_x, point_light_position_y, point_light_position_z ] ); 1134 | 1135 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexPositionBuffer ); 1136 | gl.vertexAttribPointer( shaderProgram.vertexPositionAttribute, pointLightSphereVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1137 | 1138 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexNormalBuffer ); 1139 | gl.vertexAttribPointer( shaderProgram.vertexNormalAttribute, pointLightSphereVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1140 | 1141 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexColorBuffer ); 1142 | gl.vertexAttribPointer( shaderProgram.vertexColorAttribute, pointLightSphereVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1143 | 1144 | setMatrixUniforms( ); 1145 | 1146 | gl.drawArrays( gl.TRIANGLES, 0, pointLightSphereVertexPositionBuffer.numItems ); 1147 | 1148 | mvPopMatrix( ); 1149 | 1150 | // Save the model view matrix state. 1151 | 1152 | mvPushMatrix( ); 1153 | 1154 | // Point light surface 2. 1155 | 1156 | mat4.translate( mvMatrix, mvMatrix, [ point_light_position_x1, point_light_position_y1, point_light_position_z1 ] ); 1157 | 1158 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexPositionBuffer ); 1159 | gl.vertexAttribPointer( shaderProgram.vertexPositionAttribute, pointLightSphereVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1160 | 1161 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexNormalBuffer ); 1162 | gl.vertexAttribPointer( shaderProgram.vertexNormalAttribute, pointLightSphereVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1163 | 1164 | gl.bindBuffer( gl.ARRAY_BUFFER, pointLightSphereVertexColorBuffer ); 1165 | gl.vertexAttribPointer( shaderProgram.vertexColorAttribute, pointLightSphereVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1166 | 1167 | setMatrixUniforms( ); 1168 | 1169 | gl.drawArrays( gl.TRIANGLES, 0, pointLightSphereVertexPositionBuffer.numItems ); 1170 | 1171 | mvPopMatrix( ); 1172 | 1173 | use_lighting = 1; 1174 | 1175 | } 1176 | 1177 | // Move down the negative z-axis by 25 units. 1178 | 1179 | mat4.translate( mvMatrix, mvMatrix, [ 0.0, 0.0, -25.0 ] ); 1180 | 1181 | // Save the model view matrix state. 1182 | 1183 | mvPushMatrix( ); 1184 | 1185 | // Use lighting if enabled. 1186 | 1187 | gl.uniform1i( shaderProgram.useLightingUniform, Number(use_lighting) ); 1188 | 1189 | // If normal map is enabled. 1190 | 1191 | gl.uniform1i( shaderProgram.normalMapEnabled, normal_map ); 1192 | 1193 | // Second isosurface. 1194 | 1195 | // Scale up the surface in all dimensions. 1196 | 1197 | mat4.scale( mvMatrix, mvMatrix, [ 5.0, 5.0, 5.0 ] ); 1198 | 1199 | // Rotate around the y-axis. 1200 | 1201 | mat4.rotate( mvMatrix, mvMatrix, -rotation_radians, [ 0, 1, 0 ] ); 1202 | 1203 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexPositionBuffer ); 1204 | gl.vertexAttribPointer( shaderProgram.vertexPositionAttribute, isosurface1VertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1205 | 1206 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexNormalBuffer ); 1207 | gl.vertexAttribPointer( shaderProgram.vertexNormalAttribute, isosurface1VertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1208 | 1209 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurface1VertexColorBuffer ); 1210 | gl.vertexAttribPointer( shaderProgram.vertexColorAttribute, isosurface1VertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1211 | 1212 | setMatrixUniforms( ); 1213 | 1214 | if ( Number(use_wireframe) === 0 ) 1215 | { 1216 | 1217 | gl.drawArrays( gl.TRIANGLES, 0, isosurface1VertexPositionBuffer.numItems ); 1218 | 1219 | } 1220 | else 1221 | { 1222 | 1223 | gl.drawArrays( gl.LINES, 0, isosurface1VertexPositionBuffer.numItems ); 1224 | 1225 | } 1226 | 1227 | // Restore the model view matrix state. 1228 | 1229 | mvPopMatrix( ); 1230 | 1231 | // Enable alpha blending. 1232 | 1233 | gl.blendFunc( gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); 1234 | 1235 | gl.enable( gl.BLEND ); 1236 | 1237 | alpha_blending_enabled = 1; 1238 | 1239 | gl.uniform1i( shaderProgram.alphaBlendingEnabled, alpha_blending_enabled ); 1240 | 1241 | // Save the current model view matrix for later use. 1242 | 1243 | mvPushMatrix( ); 1244 | 1245 | // First isosurface. 1246 | 1247 | mat4.scale( mvMatrix, mvMatrix, [ 11.0, 11.0, 11.0 ] ); 1248 | 1249 | // Rotate the model view matrix thereby rotating the isosurface. 1250 | 1251 | mat4.rotate( mvMatrix, mvMatrix, rotation_radians, [ 1, 1, 0 ] ); 1252 | 1253 | // Pass to the vertex shader the isosurface data. 1254 | 1255 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexPositionBuffer ); 1256 | gl.vertexAttribPointer( shaderProgram.vertexPositionAttribute, isosurfaceVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1257 | 1258 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexNormalBuffer ); 1259 | gl.vertexAttribPointer( shaderProgram.vertexNormalAttribute, isosurfaceVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1260 | 1261 | gl.bindBuffer( gl.ARRAY_BUFFER, isosurfaceVertexColorBuffer ); 1262 | gl.vertexAttribPointer( shaderProgram.vertexColorAttribute, isosurfaceVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0 ); 1263 | 1264 | setMatrixUniforms( ); 1265 | 1266 | // Render the isosurface to the screen. 1267 | 1268 | if ( Number(use_wireframe) === 0 ) 1269 | { 1270 | 1271 | gl.drawArrays( gl.TRIANGLES, 0, isosurfaceVertexPositionBuffer.numItems ); 1272 | 1273 | } 1274 | else 1275 | { 1276 | 1277 | gl.drawArrays( gl.LINES, 0, isosurfaceVertexPositionBuffer.numItems ); 1278 | 1279 | } 1280 | 1281 | // Get back the old model view matrix. 1282 | 1283 | mvPopMatrix( ); 1284 | 1285 | } 1286 | 1287 | function resize_contents( ) 1288 | { 1289 | 1290 | // The browser window has been re-sized so re-size the render window and onscreen elements. 1291 | 1292 | var logo_image = document.getElementById( "logo" ); 1293 | logo_image_height = logo_image.clientHeight; 1294 | logo_image_width = logo_image.clientWidth; 1295 | 1296 | var logo_box = document.getElementById( "logo_box" ); 1297 | logo_box.style.top = window.innerHeight - logo_image_height - 10 + "px"; 1298 | logo_box.style.left = window.innerWidth - logo_image_width - 10 + "px"; 1299 | 1300 | var canvas = document.getElementById( "webgl_canvas" ); 1301 | canvas.width = window.innerWidth; 1302 | canvas.height = window.innerHeight; 1303 | 1304 | gl.viewportWidth = canvas.width; 1305 | gl.viewportHeight = canvas.height; 1306 | 1307 | } 1308 | 1309 | function webGLStart( ) 1310 | { 1311 | 1312 | // Create and add the canvas that will be "painted" on or rather rendered to by WebGL. 1313 | 1314 | var canvas = document.createElement( "canvas" ); 1315 | canvas.id = "webgl_canvas"; 1316 | canvas.width = window.innerWidth; 1317 | canvas.height = window.innerHeight; 1318 | document.body.appendChild( canvas ); 1319 | 1320 | // Vertex shader GLSL code. 1321 | 1322 | var vertex_shader = document.createElement( "script" ); 1323 | vertex_shader.id = "shader-vs"; 1324 | vertex_shader.type = "x-shader/x-vertex"; 1325 | vertex_shader.innerHTML = "precision mediump float;"; 1326 | vertex_shader.innerHTML += "attribute vec3 aVertexPosition;"; 1327 | vertex_shader.innerHTML += "attribute vec3 aVertexNormal;"; 1328 | vertex_shader.innerHTML += "attribute vec4 aVertexColor;"; 1329 | vertex_shader.innerHTML += "uniform mat4 uMVMatrix;"; 1330 | vertex_shader.innerHTML += "uniform mat4 uPMatrix;"; 1331 | vertex_shader.innerHTML += "uniform mat3 uNMatrix;"; 1332 | vertex_shader.innerHTML += "varying vec4 vPosition;"; 1333 | vertex_shader.innerHTML += "varying vec4 vDiffuseColor;"; 1334 | vertex_shader.innerHTML += "varying vec3 vTransformedNormal;"; 1335 | vertex_shader.innerHTML += "void main( void ) {"; 1336 | vertex_shader.innerHTML += " vDiffuseColor = aVertexColor;"; 1337 | vertex_shader.innerHTML += " vTransformedNormal = uNMatrix * aVertexNormal;"; 1338 | vertex_shader.innerHTML += " vPosition = uMVMatrix * vec4( aVertexPosition, 1.0 );"; 1339 | vertex_shader.innerHTML += " gl_Position = uPMatrix * vPosition;"; 1340 | vertex_shader.innerHTML += "}"; 1341 | document.body.appendChild( vertex_shader ); 1342 | 1343 | // Fragment shader GLSL code. 1344 | 1345 | var fragment_shader = document.createElement( "script" ); 1346 | fragment_shader.id = "shader-fs"; 1347 | fragment_shader.type = "x-shader/x-fragment"; 1348 | fragment_shader.innerHTML = "precision mediump float;"; 1349 | fragment_shader.innerHTML += "uniform mat4 uPMatrix;"; 1350 | fragment_shader.innerHTML += "uniform bool uUseLighting;"; 1351 | fragment_shader.innerHTML += "uniform bool uAlphaBlendingEnabled;"; 1352 | fragment_shader.innerHTML += "uniform bool uShowDepth;"; 1353 | fragment_shader.innerHTML += "uniform bool uShowNormals;"; 1354 | fragment_shader.innerHTML += "uniform bool uShowPosition;"; 1355 | fragment_shader.innerHTML += "uniform bool uPerspectiveProjection;"; 1356 | fragment_shader.innerHTML += "uniform bool uNormalMap;"; 1357 | fragment_shader.innerHTML += "uniform vec3 uAmbientColor;"; 1358 | fragment_shader.innerHTML += "uniform vec3 uPointLightingLocation;"; 1359 | fragment_shader.innerHTML += "uniform vec3 uPointLightingColor;"; 1360 | fragment_shader.innerHTML += "uniform vec3 uPointLightingLocation1;"; 1361 | fragment_shader.innerHTML += "uniform vec3 uPointLightingColor1;"; 1362 | fragment_shader.innerHTML += "varying vec4 vPosition;"; 1363 | fragment_shader.innerHTML += "varying vec3 vTransformedNormal;"; 1364 | fragment_shader.innerHTML += "varying vec4 vDiffuseColor;"; 1365 | fragment_shader.innerHTML += "void main( void ) {"; 1366 | fragment_shader.innerHTML += " vec3 uAmbientColor = pow(uAmbientColor, vec3(2.2));"; 1367 | fragment_shader.innerHTML += " vec4 vDiffuseColor = vDiffuseColor;"; 1368 | fragment_shader.innerHTML += " vDiffuseColor.rgb = pow(vDiffuseColor.rgb, vec3(2.2));"; 1369 | fragment_shader.innerHTML += " vec3 uPointLightingColor = pow(uPointLightingColor, vec3(2.2));"; 1370 | fragment_shader.innerHTML += " vec3 uPointLightingColor1 = pow(uPointLightingColor1, vec3(2.2));"; 1371 | fragment_shader.innerHTML += " vec4 fog_color = vec4( " + base_color[ 0 ] + ", " + base_color[ 1 ] + ", " + base_color[ 2 ] + ", 1.0 );"; 1372 | fragment_shader.innerHTML += " fog_color.rgb = pow(fog_color.rgb, vec3(2.2));"; 1373 | fragment_shader.innerHTML += " vec3 ambient = vDiffuseColor.rgb * uAmbientColor;"; 1374 | fragment_shader.innerHTML += " vec3 color = ambient;"; 1375 | fragment_shader.innerHTML += " if ( uUseLighting ) {"; 1376 | fragment_shader.innerHTML += " vec3 light_direction = normalize( uPointLightingLocation - vPosition.xyz );"; 1377 | fragment_shader.innerHTML += " vec3 light_direction1 = normalize( uPointLightingLocation1 - vPosition.xyz );"; 1378 | fragment_shader.innerHTML += " vec3 eye_direction = -normalize( vPosition.xyz );"; 1379 | fragment_shader.innerHTML += " vec3 half_vector = normalize(light_direction + eye_direction);"; 1380 | fragment_shader.innerHTML += " vec3 half_vector1 = normalize(light_direction1 + eye_direction);"; 1381 | fragment_shader.innerHTML += " vec3 surface_normal;"; 1382 | fragment_shader.innerHTML += " if ( gl_FrontFacing ) {"; 1383 | fragment_shader.innerHTML += " surface_normal = normalize( vTransformedNormal );"; 1384 | fragment_shader.innerHTML += " }"; 1385 | fragment_shader.innerHTML += " else {"; 1386 | fragment_shader.innerHTML += " surface_normal = -normalize( vTransformedNormal );"; 1387 | fragment_shader.innerHTML += " }"; 1388 | fragment_shader.innerHTML += " if ( uNormalMap ) {"; 1389 | fragment_shader.innerHTML += " surface_normal = normalize( surface_normal - ( sin( dot( vDiffuseColor.rgb, vec3( 12.9898, 78.233, 1.0 ) ) ) ) );"; 1390 | fragment_shader.innerHTML += " }"; 1391 | fragment_shader.innerHTML += " vec3 diffuse = vDiffuseColor.rgb * uPointLightingColor * max( dot( surface_normal, light_direction ), 0.0 );"; 1392 | fragment_shader.innerHTML += " vec3 diffuse1 = vDiffuseColor.rgb * uPointLightingColor1 * max( dot( surface_normal, light_direction1 ), 0.0 );"; 1393 | fragment_shader.innerHTML += " vec3 specular = uPointLightingColor * pow( max( dot( half_vector, surface_normal ), 0.0 ), 100.0 );"; 1394 | fragment_shader.innerHTML += " vec3 specular1 = uPointLightingColor1 * pow( max( dot( half_vector1, surface_normal ), 0.0 ), 100.0 );"; 1395 | fragment_shader.innerHTML += " float light_outer_radius = 20.0;"; 1396 | fragment_shader.innerHTML += " float light_inner_radius = 0.0;"; 1397 | fragment_shader.innerHTML += " float light_outer_radius1 = 10.0;"; 1398 | fragment_shader.innerHTML += " float light_inner_radius1 = 0.0;"; 1399 | fragment_shader.innerHTML += " float light_distance = length( vPosition.xyz - uPointLightingLocation );"; 1400 | fragment_shader.innerHTML += " float light_distance1 = length( vPosition.xyz - uPointLightingLocation1 );"; 1401 | fragment_shader.innerHTML += " float attenuation = 1.0 - smoothstep( light_inner_radius, light_outer_radius, light_distance );"; 1402 | fragment_shader.innerHTML += " float attenuation1 = 1.0 - smoothstep( light_inner_radius1, light_outer_radius1, light_distance1 );"; 1403 | fragment_shader.innerHTML += " diffuse = attenuation * diffuse;"; 1404 | fragment_shader.innerHTML += " diffuse1 = attenuation1 * diffuse1;"; 1405 | fragment_shader.innerHTML += " specular = attenuation * specular;"; 1406 | fragment_shader.innerHTML += " specular1 = attenuation1 * specular1;"; 1407 | fragment_shader.innerHTML += " color = ambient + diffuse + diffuse1 + specular + specular1;"; 1408 | fragment_shader.innerHTML += " }"; 1409 | fragment_shader.innerHTML += " vec4 final_color;"; 1410 | fragment_shader.innerHTML += " if ( uAlphaBlendingEnabled ) {"; 1411 | fragment_shader.innerHTML += " final_color = vec4( color, vDiffuseColor.a );"; 1412 | fragment_shader.innerHTML += " }"; 1413 | fragment_shader.innerHTML += " else {"; 1414 | fragment_shader.innerHTML += " final_color = vec4( color, 1.0 );"; 1415 | fragment_shader.innerHTML += " }"; 1416 | fragment_shader.innerHTML += " float far = 50.0;"; 1417 | fragment_shader.innerHTML += " float fog_coord;"; 1418 | fragment_shader.innerHTML += " if ( uPerspectiveProjection ) {"; 1419 | fragment_shader.innerHTML += " fog_coord = ( gl_FragCoord.z / gl_FragCoord.w ) / far;"; 1420 | fragment_shader.innerHTML += " }"; 1421 | fragment_shader.innerHTML += " else {"; 1422 | fragment_shader.innerHTML += " fog_coord = ( gl_FragCoord.z / gl_FragCoord.w );"; 1423 | fragment_shader.innerHTML += " }"; 1424 | fragment_shader.innerHTML += " float fog_density = 1.5;"; 1425 | fragment_shader.innerHTML += " float fog = fog_coord * fog_density;"; 1426 | fragment_shader.innerHTML += " float fog_factor = clamp( 1.0 - fog, 0.0, 1.0 );"; 1427 | fragment_shader.innerHTML += " gl_FragColor = mix( fog_color, final_color, vec4( fog_factor, fog_factor, fog_factor, fog_factor ) );"; 1428 | fragment_shader.innerHTML += " gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / 2.2));"; 1429 | fragment_shader.innerHTML += " if ( uShowDepth ) {"; 1430 | fragment_shader.innerHTML += " gl_FragColor = mix( vec4( 1.0 ), vec4( vec3( 0.0 ), 1.0 ), smoothstep( 0.1, 1.0, fog_coord ) );"; 1431 | fragment_shader.innerHTML += " }"; 1432 | fragment_shader.innerHTML += " if ( uShowNormals ) {"; 1433 | fragment_shader.innerHTML += " vec3 nTN = normalize( vTransformedNormal );"; 1434 | fragment_shader.innerHTML += " gl_FragColor = vec4( nTN.r, nTN.g, nTN.b, 1.0 );"; 1435 | fragment_shader.innerHTML += " }"; 1436 | fragment_shader.innerHTML += " if ( uShowPosition ) {"; 1437 | fragment_shader.innerHTML += " vec3 nP = normalize( vPosition.xyz );"; 1438 | fragment_shader.innerHTML += " gl_FragColor = vec4( nP.r, nP.g, nP.b, 1.0 );"; 1439 | fragment_shader.innerHTML += " }"; 1440 | fragment_shader.innerHTML += "}"; 1441 | document.body.appendChild( fragment_shader ); 1442 | 1443 | initGL( canvas ); // Initialize WebGL. 1444 | initShaders( ); // Initialize the shaders. 1445 | initBuffers( ); // Initialize the 3D shapes. 1446 | initHUD( ); // Initialize the onscreen elements. 1447 | 1448 | gl.clearColor( base_color[ 0 ], base_color[ 1 ], base_color[ 2 ], 1.0 ); // Set the WebGL background color. 1449 | gl.enable( gl.DEPTH_TEST ); // Enable the depth buffer. 1450 | 1451 | window.requestAnimationFrame( drawScene ); // Begin rendering animation. 1452 | 1453 | } 1454 | 1455 | /* Taken from http://paulbourke.net/geometry/polygonise/ */ 1456 | 1457 | var marching_cubes_edge_table = [ 1458 | 1459 | 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 1460 | 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 1461 | 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 1462 | 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 1463 | 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 1464 | 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 1465 | 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 1466 | 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 1467 | 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 1468 | 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 1469 | 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 1470 | 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 1471 | 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 1472 | 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 1473 | 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 1474 | 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 1475 | 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 1476 | 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 1477 | 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 1478 | 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 1479 | 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 1480 | 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 1481 | 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 1482 | 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, 1483 | 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 1484 | 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, 1485 | 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 1486 | 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, 1487 | 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 1488 | 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, 1489 | 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 1490 | 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 1491 | 1492 | ]; 1493 | 1494 | var marching_cubes_triangle_table = [ 1495 | 1496 | [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1497 | [ 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1498 | [ 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1499 | [ 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1500 | [ 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1501 | [ 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1502 | [ 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1503 | [ 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 ], 1504 | [ 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1505 | [ 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1506 | [ 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1507 | [ 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 ], 1508 | [ 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1509 | [ 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 ], 1510 | [ 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 ], 1511 | [ 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1512 | [ 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1513 | [ 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1514 | [ 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1515 | [ 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 ], 1516 | [ 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1517 | [ 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 ], 1518 | [ 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 ], 1519 | [ 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 ], 1520 | [ 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1521 | [ 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 ], 1522 | [ 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 ], 1523 | [ 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 ], 1524 | [ 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 ], 1525 | [ 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 ], 1526 | [ 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 ], 1527 | [ 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 ], 1528 | [ 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1529 | [ 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1530 | [ 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1531 | [ 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 ], 1532 | [ 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1533 | [ 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 ], 1534 | [ 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 ], 1535 | [ 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 ], 1536 | [ 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1537 | [ 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 ], 1538 | [ 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 ], 1539 | [ 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 ], 1540 | [ 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 ], 1541 | [ 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 ], 1542 | [ 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 ], 1543 | [ 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 ], 1544 | [ 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1545 | [ 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 ], 1546 | [ 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 ], 1547 | [ 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1548 | [ 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 ], 1549 | [ 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 ], 1550 | [ 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 ], 1551 | [ 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 ], 1552 | [ 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 ], 1553 | [ 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 ], 1554 | [ 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 ], 1555 | [ 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 ], 1556 | [ 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 ], 1557 | [ 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 ], 1558 | [ 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 ], 1559 | [ 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1560 | [ 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1561 | [ 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1562 | [ 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1563 | [ 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 ], 1564 | [ 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1565 | [ 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 ], 1566 | [ 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 ], 1567 | [ 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 ], 1568 | [ 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1569 | [ 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 ], 1570 | [ 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 ], 1571 | [ 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 ], 1572 | [ 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 ], 1573 | [ 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 ], 1574 | [ 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 ], 1575 | [ 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 ], 1576 | [ 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1577 | [ 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 ], 1578 | [ 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 ], 1579 | [ 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 ], 1580 | [ 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 ], 1581 | [ 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 ], 1582 | [ 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 ], 1583 | [ 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 ], 1584 | [ 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 ], 1585 | [ 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 ], 1586 | [ 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 ], 1587 | [ 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 ], 1588 | [ 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 ], 1589 | [ 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 ], 1590 | [ 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 ], 1591 | [ 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 ], 1592 | [ 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1593 | [ 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 ], 1594 | [ 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 ], 1595 | [ 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 ], 1596 | [ 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 ], 1597 | [ 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 ], 1598 | [ 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1599 | [ 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 ], 1600 | [ 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 ], 1601 | [ 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 ], 1602 | [ 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 ], 1603 | [ 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 ], 1604 | [ 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 ], 1605 | [ 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 ], 1606 | [ 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 ], 1607 | [ 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1608 | [ 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 ], 1609 | [ 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 ], 1610 | [ 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 ], 1611 | [ 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 ], 1612 | [ 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 ], 1613 | [ 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 ], 1614 | [ 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 ], 1615 | [ 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1616 | [ 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 ], 1617 | [ 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 ], 1618 | [ 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 ], 1619 | [ 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 ], 1620 | [ 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 ], 1621 | [ 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1622 | [ 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 ], 1623 | [ 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1624 | [ 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1625 | [ 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1626 | [ 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1627 | [ 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 ], 1628 | [ 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1629 | [ 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 ], 1630 | [ 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 ], 1631 | [ 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 ], 1632 | [ 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1633 | [ 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 ], 1634 | [ 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 ], 1635 | [ 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 ], 1636 | [ 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 ], 1637 | [ 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 ], 1638 | [ 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 ], 1639 | [ 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 ], 1640 | [ 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1641 | [ 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 ], 1642 | [ 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 ], 1643 | [ 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 ], 1644 | [ 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 ], 1645 | [ 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 ], 1646 | [ 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 ], 1647 | [ 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 ], 1648 | [ 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 ], 1649 | [ 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1650 | [ 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 ], 1651 | [ 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 ], 1652 | [ 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 ], 1653 | [ 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 ], 1654 | [ 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 ], 1655 | [ 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1656 | [ 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1657 | [ 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 ], 1658 | [ 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 ], 1659 | [ 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 ], 1660 | [ 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 ], 1661 | [ 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 ], 1662 | [ 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 ], 1663 | [ 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 ], 1664 | [ 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 ], 1665 | [ 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 ], 1666 | [ 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 ], 1667 | [ 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 ], 1668 | [ 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 ], 1669 | [ 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 ], 1670 | [ 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 ], 1671 | [ 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 ], 1672 | [ 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 ], 1673 | [ 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 ], 1674 | [ 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 ], 1675 | [ 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 ], 1676 | [ 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 ], 1677 | [ 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 ], 1678 | [ 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 ], 1679 | [ 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 ], 1680 | [ 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 ], 1681 | [ 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 ], 1682 | [ 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 ], 1683 | [ 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1684 | [ 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 ], 1685 | [ 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 ], 1686 | [ 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1687 | [ 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1688 | [ 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1689 | [ 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 ], 1690 | [ 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 ], 1691 | [ 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 ], 1692 | [ 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 ], 1693 | [ 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 ], 1694 | [ 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 ], 1695 | [ 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 ], 1696 | [ 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 ], 1697 | [ 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 ], 1698 | [ 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 ], 1699 | [ 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 ], 1700 | [ 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1701 | [ 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 ], 1702 | [ 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 ], 1703 | [ 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1704 | [ 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 ], 1705 | [ 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 ], 1706 | [ 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 ], 1707 | [ 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 ], 1708 | [ 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 ], 1709 | [ 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 ], 1710 | [ 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 ], 1711 | [ 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1712 | [ 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 ], 1713 | [ 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 ], 1714 | [ 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 ], 1715 | [ 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 ], 1716 | [ 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 ], 1717 | [ 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1718 | [ 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 ], 1719 | [ 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1720 | [ 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 ], 1721 | [ 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 ], 1722 | [ 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 ], 1723 | [ 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 ], 1724 | [ 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 ], 1725 | [ 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 ], 1726 | [ 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 ], 1727 | [ 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 ], 1728 | [ 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 ], 1729 | [ 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 ], 1730 | [ 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 ], 1731 | [ 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1732 | [ 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 ], 1733 | [ 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 ], 1734 | [ 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1735 | [ 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1736 | [ 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1737 | [ 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 ], 1738 | [ 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 ], 1739 | [ 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1740 | [ 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 ], 1741 | [ 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 ], 1742 | [ 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1743 | [ 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1744 | [ 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 ], 1745 | [ 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1746 | [ 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 ], 1747 | [ 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1748 | [ 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1749 | [ 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1750 | [ 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], 1751 | [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ] 1752 | 1753 | ]; 1754 | --------------------------------------------------------------------------------