├── ANGMAP11.jpg ├── LICENSE ├── README.md ├── buttons.css ├── index.html ├── js ├── ImprovedNoise.js ├── Three.SubdivisionModifier.js └── Three.js ├── matcap.jpg ├── matcap2.jpg ├── matcap3.jpg ├── normal.jpg └── suzanne-raw.js /ANGMAP11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/spherical-environment-mapping/06789b67cce78e36d54b2779b00d727c706282c8/ANGMAP11.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Jaume Sanchez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Spherical Environment Mapping GLSL Shader 2 | ========================================= 3 | 4 | Code for the article "Creating a Spherical Reflection/Environment Mapping shader" 5 | http://www.clicktorelease.com/blog/creating-spherical-environment-mapping-shader 6 | 7 | License 8 | ======= 9 | 10 | MIT licensed 11 | 12 | Copyright (C) 2014 Jaume Sanchez Elias 13 | 14 | http://www.clicktorelease.com -------------------------------------------------------------------------------- /buttons.css: -------------------------------------------------------------------------------- 1 | .button { display: inline-block; padding: 7px 9px; font-size: inherit; color: #3C3C3D; text-shadow: 1px 1px 0 #FFFFFF; background: #ECECEC; white-space: nowrap; overflow: visible; cursor: pointer; text-decoration: none; border: 1px solid #CACACA; -webkit-border-radius: 2px; -moz-border-radius: 2px; -webkit-background-clip: padding-box; border-radius: 2px; outline: none; position: relative; zoom: 1; *display: inline; } 2 | .button.primary { font-weight: bold } 3 | .button:hover { color: #FFFFFF; border-color: #388AD4; text-decoration: none; text-shadow: -1px -1px 0 rgba(0,0,0,0.3); background-position: 0 -40px; background-color: #2D7DC5; } 4 | .button:active, 5 | .button.active { background-position: 0 -81px; border-color: #347BBA; background-color: #0F5EA2; color: #FFFFFF; text-shadow: none; } 6 | .button:active { top: 1px } 7 | .button.negative:hover { color: #FFFFFF; background-position: 0 -121px; background-color: #D84743; border-color: #911D1B; } 8 | .button.negative:active, 9 | .button.negative.active { background-position: 0 -161px; background-color: #A5211E; border-color: #911D1B; } 10 | .button.pill { -webkit-border-radius: 19px; -moz-border-radius: 19px; border-radius: 19px; padding: 6px 12px; } 11 | .button.left { -webkit-border-bottom-right-radius: 0px; -webkit-border-top-right-radius: 0px; -moz-border-radius-bottomright: 0px; -moz-border-radius-topright: 0px; border-bottom-right-radius: 0px; border-top-right-radius: 0px; margin-right: 0px; } 12 | .button.middle { margin-right: 0px; margin-left: 0px; -webkit-border-radius: 0px; -moz-border-radius: 0px; border-radius: 0px; border-left: none; } 13 | .button.right { -webkit-border-bottom-left-radius: 0px; -webkit-border-top-left-radius: 0px; -moz-border-radius-bottomleft: 0px; -moz-border-radius-topleft: 0px; border-top-left-radius: 0px; border-bottom-left-radius: 0px; margin-left: 0px; border-left: none;} 14 | .button.left:active, 15 | .button.middle:active, 16 | .button.right:active { top: 0px } 17 | .button.big { font-size: 16px; padding: 7px 16px; } 18 | .button span.icon { display: inline-block; width: 14px; height: 12px; margin: auto 7px auto auto; position: relative; top: 1px; background-image: url('/images/css3buttons_icons.png'); background-repeat: no-repeat; } 19 | .big.button span.icon { top: 0px } 20 | .button span.icon.book { background-position: 0 0 } 21 | .button:hover span.icon.book { background-position: 0 -15px } 22 | .button span.icon.calendar { background-position: 0 -30px } 23 | .button:hover span.icon.calendar { background-position: 0 -45px } 24 | .button span.icon.chat { background-position: 0 -60px } 25 | .button:hover span.icon.chat { background-position: 0 -75px } 26 | .button span.icon.check { background-position: 0 -90px } 27 | .button:hover span.icon.check { background-position: 0 -103px } 28 | .button span.icon.clock { background-position: 0 -116px } 29 | .button:hover span.icon.clock { background-position: 0 -131px } 30 | .button span.icon.cog { background-position: 0 -146px } 31 | .button:hover span.icon.cog { background-position: 0 -161px } 32 | .button span.icon.comment { background-position: 0 -176px } 33 | .button:hover span.icon.comment { background-position: 0 -190px } 34 | .button span.icon.cross { background-position: 0 -204px } 35 | .button:hover span.icon.cross { background-position: 0 -219px } 36 | .button span.icon.downarrow { background-position: 0 -234px } 37 | .button:hover span.icon.downarrow { background-position: 0 -249px } 38 | .button span.icon.fork { background-position: 0 -264px } 39 | .button:hover span.icon.fork { background-position: 0 -279px } 40 | .button span.icon.heart { background-position: 0 -294px } 41 | .button:hover span.icon.heart { background-position: 0 -308px } 42 | .button span.icon.home { background-position: 0 -322px } 43 | .button:hover span.icon.home { background-position: 0 -337px } 44 | .button span.icon.key { background-position: 0 -352px } 45 | .button:hover span.icon.key { background-position: 0 -367px } 46 | .button span.icon.leftarrow { background-position: 0 -382px } 47 | .button:hover span.icon.leftarrow { background-position: 0 -397px } 48 | .button span.icon.lock { background-position: 0 -412px } 49 | .button:hover span.icon.lock { background-position: 0 -427px } 50 | .button span.icon.loop { background-position: 0 -442px } 51 | .button:hover span.icon.loop { background-position: 0 -457px } 52 | .button span.icon.magnifier { background-position: 0 -472px } 53 | .button:hover span.icon.magnifier { background-position: 0 -487px } 54 | .button span.icon.mail { background-position: 0 -502px } 55 | .button:hover span.icon.mail { background-position: 0 -514px } 56 | .button span.icon.move { background-position: 0 -526px } 57 | .button:hover span.icon.move { background-position: 0 -541px } 58 | .button span.icon.pen { background-position: 0 -556px } 59 | .button:hover span.icon.pen { background-position: 0 -571px } 60 | .button span.icon.pin { background-position: 0 -586px } 61 | .button:hover span.icon.pin { background-position: 0 -601px } 62 | .button span.icon.plus { background-position: 0 -616px } 63 | .button:hover span.icon.plus { background-position: 0 -631px } 64 | .button span.icon.reload { background-position: 0 -646px } 65 | .button:hover span.icon.reload { background-position: 0 -660px } 66 | .button span.icon.rightarrow { background-position: 0 -674px } 67 | .button:hover span.icon.rightarrow { background-position: 0 -689px } 68 | .button span.icon.rss { background-position: 0 -704px } 69 | .button:hover span.icon.rss { background-position: 0 -719px } 70 | .button span.icon.tag { background-position: 0 -734px } 71 | .button:hover span.icon.tag { background-position: 0 -749px } 72 | .button span.icon.trash { background-position: 0 -764px } 73 | .button:hover span.icon.trash { background-position: 0 -779px } 74 | .button span.icon.unlock { background-position: 0 -794px } 75 | .button:hover span.icon.unlock { background-position: 0 -809px } 76 | .button span.icon.uparrow { background-position: 0 -824px } 77 | .button:hover span.icon.uparrow { background-position: 0 -839px } 78 | .button span.icon.user { background-position: 0 -854px } 79 | .button:hover span.icon.user { background-position: 0 -869px } 80 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Spherical Environment Mapping (MatCap/LitSphere) 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 63 | 64 | 65 | 66 |
67 |
68 |

Spherical Environment Mapping [↑]

69 |

Example of Spherical Environment Mapping (SEM) on different meshes and materials.
Click and drag to rotate, mousewheel to zoom in and out. Try the options
on the right to change mesh, material and shading interpolation.

70 |

Check out this more complex example using SEM and bump mapping:
Spherical Environment Mapping (MatCap/LitSphere) and Normal Mapping

71 |

Read the whole article here. By Jaume Sanchez @thespite

72 |

Fork on GitHub

73 |
74 |
75 | 76 |
77 |

Model

78 | 83 |
84 | 85 |
86 |

Material

87 | 92 |
93 | 94 |
95 | 96 |

Frame time:

97 |
98 | 99 |
100 | 101 | 102 | 103 | 104 | 105 | 106 | 124 | 125 | 139 | 140 | 155 | 156 | 177 | 178 | 636 | 637 | 638 | 639 | -------------------------------------------------------------------------------- /js/ImprovedNoise.js: -------------------------------------------------------------------------------- 1 | // http://mrl.nyu.edu/~perlin/noise/ 2 | 3 | var ImprovedNoise = function () { 4 | 5 | var p = [151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10, 6 | 23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87, 7 | 174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211, 8 | 133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208, 9 | 89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5, 10 | 202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119, 11 | 248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232, 12 | 178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249, 13 | 14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205, 14 | 93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180]; 15 | 16 | for (var i=0; i < 256 ; i++) { 17 | 18 | p[256+i] = p[i]; 19 | 20 | } 21 | 22 | function fade(t) { 23 | 24 | return t * t * t * (t * (t * 6 - 15) + 10); 25 | 26 | } 27 | 28 | function lerp(t, a, b) { 29 | 30 | return a + t * (b - a); 31 | 32 | } 33 | 34 | function grad(hash, x, y, z) { 35 | 36 | var h = hash & 15; 37 | var u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z; 38 | return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v); 39 | 40 | } 41 | 42 | return { 43 | 44 | noise: function (x, y, z) { 45 | 46 | var floorX = Math.floor(x), floorY = Math.floor(y), floorZ = Math.floor(z); 47 | 48 | var X = floorX & 255, Y = floorY & 255, Z = floorZ & 255; 49 | 50 | x -= floorX; 51 | y -= floorY; 52 | z -= floorZ; 53 | 54 | var xMinus1 = x -1, yMinus1 = y - 1, zMinus1 = z - 1; 55 | 56 | var u = fade(x), v = fade(y), w = fade(z); 57 | 58 | var A = p[X]+Y, AA = p[A]+Z, AB = p[A+1]+Z, B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z; 59 | 60 | return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), 61 | grad(p[BA], xMinus1, y, z)), 62 | lerp(u, grad(p[AB], x, yMinus1, z), 63 | grad(p[BB], xMinus1, yMinus1, z))), 64 | lerp(v, lerp(u, grad(p[AA+1], x, y, zMinus1), 65 | grad(p[BA+1], xMinus1, y, z-1)), 66 | lerp(u, grad(p[AB+1], x, yMinus1, zMinus1), 67 | grad(p[BB+1], xMinus1, yMinus1, zMinus1)))); 68 | 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /js/Three.SubdivisionModifier.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog 3 | * 4 | * Subdivision Geometry Modifier 5 | * using Catmull-Clark Subdivision Surfaces 6 | * for creating smooth geometry meshes 7 | * 8 | * Note: a modifier modifies vertices and faces of geometry, 9 | * so use geometry.clone() if original geometry needs to be retained 10 | * 11 | * Readings: 12 | * http://en.wikipedia.org/wiki/Catmull%E2%80%93Clark_subdivision_surface 13 | * http://www.rorydriscoll.com/2008/08/01/catmull-clark-subdivision-the-basics/ 14 | * http://xrt.wikidot.com/blog:31 15 | * "Subdivision Surfaces in Character Animation" 16 | * 17 | * (on boundary edges) 18 | * http://rosettacode.org/wiki/Catmull%E2%80%93Clark_subdivision_surface 19 | * https://graphics.stanford.edu/wikis/cs148-09-summer/Assignment3Description 20 | * 21 | * Supports: 22 | * Closed and Open geometries. 23 | * 24 | * TODO: 25 | * crease vertex and "semi-sharp" features 26 | * selective subdivision 27 | */ 28 | 29 | 30 | THREE.SubdivisionModifier = function ( subdivisions ) { 31 | 32 | this.subdivisions = (subdivisions === undefined ) ? 1 : subdivisions; 33 | 34 | // Settings 35 | this.useOldVertexColors = false; 36 | this.supportUVs = true; 37 | this.debug = false; 38 | 39 | }; 40 | 41 | // Applies the "modify" pattern 42 | THREE.SubdivisionModifier.prototype.modify = function ( geometry ) { 43 | 44 | var repeats = this.subdivisions; 45 | 46 | while ( repeats-- > 0 ) { 47 | this.smooth( geometry ); 48 | } 49 | 50 | }; 51 | 52 | /// REFACTORING THIS OUT 53 | 54 | THREE.GeometryUtils.orderedKey = function ( a, b ) { 55 | 56 | return Math.min( a, b ) + "_" + Math.max( a, b ); 57 | 58 | }; 59 | 60 | 61 | // Returns a hashmap - of { edge_key: face_index } 62 | THREE.GeometryUtils.computeEdgeFaces = function ( geometry ) { 63 | 64 | var i, il, v1, v2, j, k, 65 | face, faceIndices, faceIndex, 66 | edge, 67 | hash, 68 | edgeFaceMap = {}; 69 | 70 | var orderedKey = THREE.GeometryUtils.orderedKey; 71 | 72 | function mapEdgeHash( hash, i ) { 73 | 74 | if ( edgeFaceMap[ hash ] === undefined ) { 75 | 76 | edgeFaceMap[ hash ] = []; 77 | 78 | } 79 | 80 | edgeFaceMap[ hash ].push( i ); 81 | } 82 | 83 | 84 | // construct vertex -> face map 85 | 86 | for( i = 0, il = geometry.faces.length; i < il; i ++ ) { 87 | 88 | face = geometry.faces[ i ]; 89 | 90 | if ( face instanceof THREE.Face3 ) { 91 | 92 | hash = orderedKey( face.a, face.b ); 93 | mapEdgeHash( hash, i ); 94 | 95 | hash = orderedKey( face.b, face.c ); 96 | mapEdgeHash( hash, i ); 97 | 98 | hash = orderedKey( face.c, face.a ); 99 | mapEdgeHash( hash, i ); 100 | 101 | } else if ( face instanceof THREE.Face4 ) { 102 | 103 | hash = orderedKey( face.a, face.b ); 104 | mapEdgeHash( hash, i ); 105 | 106 | hash = orderedKey( face.b, face.c ); 107 | mapEdgeHash( hash, i ); 108 | 109 | hash = orderedKey( face.c, face.d ); 110 | mapEdgeHash( hash, i ); 111 | 112 | hash = orderedKey( face.d, face.a ); 113 | mapEdgeHash( hash, i ); 114 | 115 | } 116 | 117 | } 118 | 119 | // extract faces 120 | 121 | // var edges = []; 122 | // 123 | // var numOfEdges = 0; 124 | // for (i in edgeFaceMap) { 125 | // numOfEdges++; 126 | // 127 | // edge = edgeFaceMap[i]; 128 | // edges.push(edge); 129 | // 130 | // } 131 | 132 | //debug('edgeFaceMap', edgeFaceMap, 'geometry.edges',geometry.edges, 'numOfEdges', numOfEdges); 133 | 134 | return edgeFaceMap; 135 | 136 | } 137 | 138 | ///////////////////////////// 139 | 140 | // Performs an iteration of Catmull-Clark Subdivision 141 | THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) { 142 | 143 | //debug( 'running smooth' ); 144 | 145 | // New set of vertices, faces and uvs 146 | var newVertices = [], newFaces = [], newUVs = []; 147 | 148 | function v( x, y, z ) { 149 | newVertices.push( new THREE.Vector3( x, y, z ) ); 150 | } 151 | 152 | var scope = this; 153 | var orderedKey = THREE.GeometryUtils.orderedKey; 154 | var computeEdgeFaces = THREE.GeometryUtils.computeEdgeFaces; 155 | 156 | function assert() { 157 | 158 | if (scope.debug && console && console.assert) console.assert.apply(console, arguments); 159 | 160 | } 161 | 162 | function debug() { 163 | 164 | if (scope.debug) console.log.apply(console, arguments); 165 | 166 | } 167 | 168 | function warn() { 169 | 170 | if (console) 171 | console.log.apply(console, arguments); 172 | 173 | } 174 | 175 | function f4( a, b, c, d, oldFace, orders, facei ) { 176 | 177 | // TODO move vertex selection over here! 178 | 179 | var newFace = new THREE.Face4( a, b, c, d, null, oldFace.color, oldFace.materialIndex ); 180 | 181 | if (scope.useOldVertexColors) { 182 | 183 | newFace.vertexColors = []; 184 | 185 | var color, tmpColor, order; 186 | 187 | for (var i=0;i<4;i++) { 188 | 189 | order = orders[i]; 190 | 191 | color = new THREE.Color(), 192 | color.setRGB(0,0,0); 193 | 194 | for (var j=0, jl=0; j=originalVerticesLength && vertexNo < (originalVerticesLength + originalFaces.length)) { 262 | debug('face pt'); 263 | } else { 264 | debug('edge pt'); 265 | } 266 | 267 | warn('warning, UV not found for', key); 268 | 269 | return null; 270 | } 271 | 272 | return theUV; 273 | 274 | // Original faces -> Vertex Nos. 275 | // new Facepoint -> Vertex Nos. 276 | // edge Points 277 | 278 | } 279 | 280 | function addUV(vertexNo, oldFaceNo, value) { 281 | 282 | var key = vertexNo+':'+oldFaceNo; 283 | if (!(key in uvForVertices)) { 284 | uvForVertices[key] = value; 285 | } else { 286 | warn('dup vertexNo', vertexNo, 'oldFaceNo', oldFaceNo, 'value', value, 'key', key, uvForVertices[key]); 287 | } 288 | } 289 | 290 | // Step 1 291 | // For each face, add a face point 292 | // Set each face point to be the centroid of all original points for the respective face. 293 | // debug(oldGeometry); 294 | var i, il, j, jl, face; 295 | 296 | // For Uvs 297 | var uvs = oldGeometry.faceVertexUvs[0]; 298 | var abcd = 'abcd', vertice; 299 | 300 | debug('originalFaces, uvs, originalVerticesLength', originalFaces.length, uvs.length, originalVerticesLength); 301 | 302 | if (scope.supportUVs) 303 | 304 | for (i=0, il = uvs.length; i Faces Index eg { edge_key: [face_index, face_index2 ]} 366 | var edge, faceIndexA, faceIndexB, avg; 367 | 368 | // debug('edgeFaceMap', edgeFaceMap); 369 | 370 | var edgeCount = 0; 371 | 372 | var edgeVertex, edgeVertexA, edgeVertexB; 373 | 374 | //// 375 | 376 | var vertexEdgeMap = {}; // Gives edges connecting from each vertex 377 | var vertexFaceMap = {}; // Gives faces connecting from each vertex 378 | 379 | function addVertexEdgeMap(vertex, edge) { 380 | 381 | if (vertexEdgeMap[vertex]===undefined) { 382 | 383 | vertexEdgeMap[vertex] = []; 384 | 385 | } 386 | 387 | vertexEdgeMap[vertex].push(edge); 388 | } 389 | 390 | function addVertexFaceMap(vertex, face, edge) { 391 | 392 | if (vertexFaceMap[vertex]===undefined) { 393 | 394 | vertexFaceMap[vertex] = {}; 395 | 396 | } 397 | 398 | vertexFaceMap[vertex][face] = edge; 399 | // vertexFaceMap[vertex][face] = null; 400 | } 401 | 402 | // Prepares vertexEdgeMap and vertexFaceMap 403 | for (i in edgeFaceMap) { // This is for every edge 404 | edge = edgeFaceMap[i]; 405 | 406 | edgeVertex = i.split('_'); 407 | edgeVertexA = edgeVertex[0]; 408 | edgeVertexB = edgeVertex[1]; 409 | 410 | // Maps an edgeVertex to connecting edges 411 | addVertexEdgeMap(edgeVertexA, [edgeVertexA, edgeVertexB] ); 412 | addVertexEdgeMap(edgeVertexB, [edgeVertexA, edgeVertexB] ); 413 | 414 | for (j=0,jl=edge.length;j 0, 'an edge without faces?!'); 452 | 453 | if (edge.length==1) { 454 | 455 | avg.add( originalPoints[ edgeVertexA ] ); 456 | avg.add( originalPoints[ edgeVertexB ] ); 457 | avg.multiplyScalar( 0.5 ); 458 | 459 | sharpVertices[newPoints.length] = true; 460 | 461 | } else { 462 | 463 | avg.add( facePoints[ faceIndexA ] ); 464 | avg.add( facePoints[ faceIndexB ] ); 465 | 466 | avg.add( originalPoints[ edgeVertexA ] ); 467 | avg.add( originalPoints[ edgeVertexB ] ); 468 | 469 | avg.multiplyScalar( 0.25 ); 470 | 471 | } 472 | 473 | edgePoints[i] = originalVerticesLength + originalFaces.length + edgeCount; 474 | 475 | newPoints.push( avg ); 476 | 477 | edgeCount ++; 478 | 479 | if (!scope.supportUVs) { 480 | continue; 481 | } 482 | 483 | // Prepare subdivided uv 484 | 485 | avgUv = new THREE.Vector2(); 486 | 487 | avgUv.x = getUV(edgeVertexA, faceIndexA).x + getUV(edgeVertexB, faceIndexA).x; 488 | avgUv.y = getUV(edgeVertexA, faceIndexA).y + getUV(edgeVertexB, faceIndexA).y; 489 | avgUv.x /= 2; 490 | avgUv.y /= 2; 491 | 492 | addUV(edgePoints[i], faceIndexA, avgUv); 493 | 494 | if (edge.length>=2) { 495 | assert(edge.length == 2, 'did we plan for more than 2 edges?'); 496 | avgUv = new THREE.Vector2(); 497 | 498 | avgUv.x = getUV(edgeVertexA, faceIndexB).x + getUV(edgeVertexB, faceIndexB).x; 499 | avgUv.y = getUV(edgeVertexA, faceIndexB).y + getUV(edgeVertexB, faceIndexB).y; 500 | avgUv.x /= 2; 501 | avgUv.y /= 2; 502 | 503 | addUV(edgePoints[i], faceIndexB, avgUv); 504 | } 505 | 506 | } 507 | 508 | debug('-- Step 2 done'); 509 | 510 | // Step 3 511 | // For each face point, add an edge for every edge of the face, 512 | // connecting the face point to each edge point for the face. 513 | 514 | var facePt, currentVerticeIndex; 515 | 516 | var hashAB, hashBC, hashCD, hashDA, hashCA; 517 | 518 | var abc123 = ['123', '12', '2', '23']; 519 | var bca123 = ['123', '23', '3', '31']; 520 | var cab123 = ['123', '31', '1', '12']; 521 | var abc1234 = ['1234', '12', '2', '23']; 522 | var bcd1234 = ['1234', '23', '3', '34']; 523 | var cda1234 = ['1234', '34', '4', '41']; 524 | var dab1234 = ['1234', '41', '1', '12']; 525 | 526 | for (i=0, il = facePoints.length; i2) { 623 | // TODO 624 | } 625 | */ 626 | 627 | F.divideScalar(f); 628 | 629 | 630 | var boundary_edges = 0; 631 | 632 | if (boundary_case) { 633 | 634 | var bb_edge; 635 | for (j=0; j