├── .gitignore ├── README.md ├── assets ├── in_out_test.ai ├── in_out_test.png ├── models │ ├── binaries │ │ ├── chthulu.bin │ │ ├── chthulu.js │ │ ├── dwarf.bin │ │ ├── dwarf.js │ │ ├── plane.bin │ │ ├── plane.js │ │ ├── spider.bin │ │ ├── spider.js │ │ ├── suzanne.bin │ │ ├── suzanne.js │ │ ├── suzanne_invert.bin │ │ └── suzanne_invert.js │ └── particles │ │ ├── dwarf │ │ ├── dwarf2k.txt │ │ ├── dwarf32k.txt │ │ └── dwarf4k.txt │ │ ├── plane │ │ └── plane65k.txt │ │ ├── spider │ │ └── spider32k.txt │ │ └── suzanne │ │ ├── skeleton65k.txt │ │ └── volume65k.txt ├── normals.png ├── source │ ├── BK_WIDOW │ │ ├── BK_WIDOW.3DS │ │ ├── BK_WIDOW.DXF │ │ ├── BK_WIDOW.JPG │ │ ├── BK_WIDOW.LWO │ │ ├── BK_WIDOW.MTL │ │ ├── BK_WIDOW.OBJ │ │ └── BK_WIDOW.TIF │ ├── chthulu.max │ ├── convert.py │ ├── dwarf.obj │ ├── plane.obj │ ├── skeleton.max │ ├── skeleton │ │ ├── skeleton.3DS │ │ ├── skeleton.max │ │ ├── skeleton.mtl │ │ └── skeleton.obj │ ├── skeletor.obj │ ├── skull.max │ ├── spider.max │ └── suzanne.max ├── textures │ ├── matcap │ │ ├── 00ZBrush_RedWax.png │ │ ├── BazC_SkinMat.jpg │ │ ├── JGSpecial_01.png │ │ ├── JG_Drink01.png │ │ ├── JG_Gold.png │ │ ├── JG_Red.png │ │ ├── chrome_dark.png │ │ ├── chrome_eye.png │ │ ├── close_to_50.png │ │ ├── darker.jpg │ │ ├── droplet_01.png │ │ ├── env.png │ │ ├── generator1.jpg │ │ ├── generator3.jpg │ │ ├── generator5.jpg │ │ ├── generator6.jpg │ │ ├── generator7.jpg │ │ ├── generator8.jpg │ │ ├── generator9.jpg │ │ ├── genetic.png │ │ ├── ghost.jpg │ │ ├── gold.png │ │ ├── green_gel.png │ │ ├── grey_reflective.jpg │ │ ├── index.json │ │ ├── mashrim.png │ │ ├── mashrim2.jpg │ │ ├── matcap.png │ │ ├── material2.png │ │ ├── material3.jpg │ │ ├── material4.png │ │ ├── mshade3.jpg │ │ ├── mshade4.jpg │ │ ├── mshade5.jpg │ │ ├── normals.jpg │ │ ├── old_gold.png │ │ ├── red_bob.jpg │ │ ├── red_clay.jpg │ │ ├── right_light.jpg │ │ ├── scary-light.jpg │ │ ├── silver.jpg │ │ ├── skintone.jpg │ │ ├── softunderlight.png │ │ ├── strong rim.png │ │ ├── test_gold.jpg │ │ ├── test_steel.jpg │ │ ├── thuggle.jpg │ │ ├── thuglee-03.jpg │ │ ├── thuglee-backlight-01.jpg │ │ ├── thuglee-chrome-02b.jpg │ │ └── untitled.6.jpg │ └── particles.png └── valid.png ├── dwarf.html ├── glsl ├── env_fs.glsl ├── env_vs.glsl ├── line_sem_fs.glsl ├── line_sem_vs.glsl ├── meshline_fs.glsl ├── meshline_vs.glsl ├── particles_fs.glsl ├── particles_vs.glsl ├── sem_fs.glsl ├── sem_vs.glsl ├── texture_particles_fs.glsl ├── texture_particles_vs.glsl └── tmp ├── img ├── dwarf.jpg ├── plane.jpg ├── spider.jpg ├── suzanne.jpg └── suzanne_distribution.jpg ├── js ├── common │ ├── Scatter.js │ ├── assetsLoader.js │ └── scene3d.js ├── dwarf.js ├── dwarf_bk.js ├── plane.js ├── spider.js └── suzanne.js ├── plane.html ├── spider.html ├── sreenshots ├── 4k.png ├── 4k0.png ├── 4k1.png ├── 4k2.png ├── 4k3.png ├── 8k0.png ├── 8k1.png ├── lines0.png ├── lines1.png └── spider0.png ├── suzanne.html └── vendor ├── BinaryLoader.js ├── OrbitControls.js ├── THREE.MeshLine.js └── three.js /.gitignore: -------------------------------------------------------------------------------- 1 | #ignore thumbnails created by windows 2 | Thumbs.db 3 | /sreenshots/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # volume distribution 2 | distributing 3D vectors inside a mesh with THREE.js 3 | 4 | ![principle](img/suzanne.jpg) 5 | this post and demos are also [available here](http://barradeau.com/blog/?p=1058) 6 | 7 | the idea is to distribute (scatter) a set of random 3D points inside a volume, preferably an arbitrary mesh. 8 | 9 | distributing random points in geometric volumes is quite straight forward. if you know the formula of a sphere, a cube, a cylinder or any shape, you can create a point inside the said shape. also, and much like Constructive Solid Geometry, it’s fairly easy to use boolean operations (union, subtraction, intersection & XOR) between the shapes and obtain a broad variety of complex shapes. 10 | 11 | if this approach is elegant, probably fast and efficient, it has a big downside ; arbitrary meshes are hard – if not impossible – to model with equations. it is therefore often limited to simple use cases like procedural or fractals shapes. 12 | 13 | being a long time 3DS max user, I often used the “Scatter” modifier to distribute point on or inside a mesh. when I used a non-manifold polyhedron – a “broken” mesh, with holes, no inside or outside – the modifier failed or 3DS crashed. that’s when I decided to try to code something. 14 | 15 | the algorithm goes as follow: 16 | 17 | * pick a random point on the bounding volume of the mesh and a random direction 18 | * shoot a ray at the mesh from that origin, in that direction 19 | * evaluate the result to keep or discard the intersection points 20 | it implies shooting many rays at a mesh so depending on the mesh’s complexity, it can take a lot of time and anyway it’s more suited as a mesh “pre-processor” than as a real time modifier. 21 | 22 | step 1 is trivial, for step 2, THREE.js has a built-in raycaster and for step 3, we’ll mostly need to determine if we’re ‘inside’ or ‘outside’ the mesh. 23 | 24 | to determine if a point is inside or outside a polyhedron, assuming the mesh is a manifold (it has an ‘inside’ and an ‘outside’), we can shoot a ray from that point in any direction and count how many times the ray intersects the polyhedron. 25 | 26 | if the number is even, your point is outside, if it’s odd, it’s inside. a visual explanation: 27 | 28 | ![octopus](assets/in_out_test.png) 29 | 30 | I think it also works with actual octopuses but I would recommend not to try. 31 | 32 | essentially, we’ll use the number of times a ray intersects the mesh to determine wether we’re inside or outside. here’s my implementation: 33 | 34 | ```javascript 35 | var raycaster;//THREE.raycaster: used to shoot rays at the mesh 36 | var o;//ray origin 37 | var d;//ray direction 38 | var intersections;//stores the result of the raycasting 39 | var a;//DOM element tag to download the result ( see particlesToString ) 40 | 41 | function distribute( mesh, count ) { 42 | 43 | //this will store the results 44 | var coords = []; 45 | var dests = []; 46 | //temporary vars to store the position and destination 47 | var p0, p1; 48 | 49 | //this has an influence as to how the raycasting is performed 50 | var side = mesh.material.side; 51 | mesh.material.side = THREE.DoubleSide; 52 | 53 | //we'll need normals (it's probably done implicitly when we raycast though) 54 | mesh.geometry.computeFaceNormals(); 55 | 56 | //this is used to distributte the origins of the rays 57 | mesh.geometry.computeBoundingBox(); 58 | var bbox = mesh.geometry.boundingBox; 59 | 60 | // 'inflates' the box by 10% to prevent colinearity 61 | // or coplanarity of the origin with the mesh 62 | bbox.min.multiplyScalar( 1.1 ); 63 | bbox.max.multiplyScalar( 1.1 ); 64 | 65 | //computes the box' size to compute random points 66 | var size = bbox.max.sub( bbox.min ); 67 | 68 | //to perform raycast 69 | raycaster = raycaster || new THREE.Raycaster(); 70 | o = o || new THREE.Vector3(); 71 | d = d || new THREE.Vector3(); 72 | 73 | for( var i = 0; i < count; i++ ){ 74 | 75 | // randomize the rays origin 76 | o.x = bbox.min.x + Math.random() * size.x; 77 | o.y = bbox.min.y + Math.random() * size.y; 78 | o.z = bbox.min.z + Math.random() * size.z; 79 | 80 | //randomize the ray's direction 81 | d.x = ( Math.random() - .5 ); 82 | d.y = ( Math.random() - .5 ); 83 | d.z = ( Math.random() - .5 ); 84 | d.normalize(); 85 | 86 | //sets the raycaster 87 | raycaster.set( o, d ); 88 | 89 | //shoots the ray 90 | intersections = raycaster.intersectObject( mesh, false ); 91 | 92 | //no result 93 | if( intersections.length == 0 ){ 94 | 95 | //bail out & continue 96 | i--; 97 | 98 | }else{ 99 | 100 | //checks if we meet the conditions: 101 | //the origin must be outside 102 | var valid = intersections.length >= 2 && (intersections.length % 2==0); 103 | if (valid) { 104 | 105 | //tests all the intersection pairs 106 | var additions = -1; 107 | for( var j = 0; j < intersections.length; j+= 2 ){ 108 | 109 | // make sure that the origin -> direction vector have the same 110 | // direction as the normal of the face they hit 111 | 112 | //test the direction against the outwards' face's normal 113 | var dp0 = d.dot(intersections[ j + 1 ].face.normal) <= 0; 114 | 115 | //flips the direction to make it 'look at' the origin 116 | d.negate(); 117 | 118 | //test the direction against the inwards' face's normal 119 | var dp1 = d.dot(intersections[ j ].face.normal) <= 0; 120 | 121 | //flips the direction again for the next test 122 | d.negate(); 123 | 124 | // if both vectors pairs head in the same direction 125 | // the point is guarranteed to be inside 126 | if( dp0 || dp1){ 127 | continue; 128 | } 129 | 130 | //adds the points 131 | if( coords.length < count * 3 ){ 132 | console.log("ok") 133 | p0 = intersections[j].point; 134 | coords.push( p0.x, p0.y, p0.z); 135 | p1 = intersections[j+1].point; 136 | dests.push( p1.x, p1.y, p1.z); 137 | additions++; 138 | } 139 | } 140 | //increments the counter by the number of additions 141 | i += additions; 142 | 143 | }else{ 144 | //invalid intersection, try again... 145 | i--; 146 | } 147 | } 148 | } 149 | //resets the material side 150 | mesh.material.side = side; 151 | return { 152 | pos:coords, 153 | dst:dests 154 | }; 155 | }; 156 | ``` 157 | this is rather self-explanatory (hopefully) ; we get the bounding box of the mesh, ‘inflate’ it a bit to avoid some colinearity / coplanarity issues, then randomize the ray’s origin/direction. performa ray casting onto the mesh then classify the result. 158 | 159 | let’s focus on the ‘classify’ bit a minute: 160 | 161 | 162 | ```javascript 163 | //the origin must be outside 164 | var valid = intersections.length >= 2 && ( intersections.length % 2 == 0 ); 165 | if (valid) { 166 | [...] 167 | ``` 168 | we’re in a valid state if we have: at least 2 intersections and an even number of intersections which means that we hit the mesh at least once and our origin is outside the mesh ( as seen above with that glorious octopus illustration ). we have something like this when valid is true: 169 | valid 170 | ![valid case](assets/valid.png) 171 | 172 | the next bit takes all pairs of points and retrieves the associated normals like so: 173 | ![valid case](assets/normals.png) 174 | and computes the dot product between the 2 vectors of the same color. if the dot product of 2 vectors is positive, they’re heading in the same direction, if the dot product is negative, they are heading in opposite directions and if it’s 0, they are perpendicular. this dreadful 4 liners will do this for all intersections pairs. 175 | 176 | ```javascript 177 | //test the direction against the outwards' face's normal 178 | var dp0 = d.dot(intersections[ j + 1 ].face.normal) <= 0; 179 | 180 | //flips the direction to make it 'look at' the origin 181 | d.negate(); 182 | 183 | //test the direction against the inwards' face's normal 184 | var dp1 = d.dot(intersections[ j ].face.normal) <= 0; 185 | 186 | //flips the direction again for the next test 187 | d.negate(); 188 | 189 | // if both vectors pairs head in the same direction 190 | // the point is guarranteed to be inside 191 | if( dp0 || dp1){ 192 | continue; 193 | } 194 | ``` 195 | this ensures that the “broken polyhedra” work too ; if the 2 faces’ normals head in the same direction, the object is broken ; it has no inside or outside. the code above checks this case and bails out if need be. it can also collect more than 2 points per ray which is nice :) 196 | 197 | you would call it like: 198 | 199 | ```javascript 200 | var model = CHTHULU;//a THREE.Mesh 201 | var count = Math.pow( 2, 12 );// -> 4096 point pairs 202 | 203 | //call the method and strore the result in a prticles object 204 | var inside = distribute( model, count ); 205 | ``` 206 | 207 | the result of the distribute function is a pair of float32Arrays containing XYZ triplets for the in & out positions respectively. to place an object ‘inside’ the polyhedron, you’d do something like: 208 | 209 | ```javascript 210 | //midpoint of the 2 intersection points 211 | var p = new THREE.Vector3( 212 | ( inside.pos[ id ].x + inside.dst[ id ].x ) * .5, 213 | ( inside.pos[ id ].y + inside.dst[ id ].y ) * .5, 214 | ( inside.pos[ id ].z + inside.dst[ id ].z ) * .5 215 | ); 216 | ``` 217 | 218 | or more likely, pass inside.dst as an attribute and ask the shader to mix the two: 219 | ```glsl 220 | float t = abs( sin( time ) ); 221 | vec3 pos = mix( position, dest, t ); 222 | ``` 223 | 224 | with a value t between 0 & 1 which guarantees that the position will remain inside the mesh. 225 | 226 | of course we can change the above to ‘carve’ the mesh inside a cloud of points and keep only the “outside”. :) 227 | 228 | HAMMER TIME! 229 | this is a model with 65K particles floating around (click) 230 | 231 | [![principle](img/suzanne.jpg)](http://www.barradeau.com/2017/volume/suzanne.html) 232 | 233 | if you notice some particles floating around, it’s because the distribution mesh is the mother of all non-manifold polyhedra ^^ 234 | ![principle](img/suzanne_distribution.jpg) 235 | 236 | this is again 65K particles distributed inside a mesh. notice how it retained the fine details (on the legs for instance) 237 | 238 | [![principle](img/spider.jpg)](http://www.barradeau.com/2017/volume/spider.html) 239 | 240 | still 65K particles, this time rendered as line segments 241 | 242 | [![principle](img/plane.jpg)](http://www.barradeau.com/2017/volume/plane.html) 243 | 244 | finally a splendid rendition of 2K particles as line sets, using the Spite’s MeshLines. my code is ugly as fuck but hey… 245 | 246 | [![principle](img/dwarf.jpg)](http://www.barradeau.com/2017/volume/dwarf.html) 247 | 248 | and that’s it! well, I gues you get the idea ^^ 249 | enjoy :) -------------------------------------------------------------------------------- /assets/in_out_test.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/in_out_test.ai -------------------------------------------------------------------------------- /assets/in_out_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/in_out_test.png -------------------------------------------------------------------------------- /assets/models/binaries/chthulu.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/models/binaries/chthulu.bin -------------------------------------------------------------------------------- /assets/models/binaries/chthulu.js: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "metadata" : 4 | { 5 | "formatVersion" : 3.1, 6 | "sourceFile" : "chthulu.obj", 7 | "generatedBy" : "OBJConverter", 8 | "vertices" : 1751, 9 | "faces" : 3488, 10 | "normals" : 0, 11 | "uvs" : 0, 12 | "materials" : 0 13 | }, 14 | 15 | "materials": [ { 16 | "DbgColor" : 15658734, 17 | "DbgIndex" : 0, 18 | "DbgName" : "default" 19 | }], 20 | 21 | "buffers": "chthulu.bin" 22 | 23 | } 24 | -------------------------------------------------------------------------------- /assets/models/binaries/dwarf.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/models/binaries/dwarf.bin -------------------------------------------------------------------------------- /assets/models/binaries/dwarf.js: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "metadata" : 4 | { 5 | "formatVersion" : 3.1, 6 | "sourceFile" : "dwarf.obj", 7 | "generatedBy" : "OBJConverter", 8 | "vertices" : 3083, 9 | "faces" : 6166, 10 | "normals" : 0, 11 | "uvs" : 0, 12 | "materials" : 0 13 | }, 14 | 15 | "materials": [ { 16 | "DbgColor" : 15658734, 17 | "DbgIndex" : 0, 18 | "DbgName" : "default" 19 | }], 20 | 21 | "buffers": "dwarf.bin" 22 | 23 | } 24 | -------------------------------------------------------------------------------- /assets/models/binaries/plane.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/models/binaries/plane.bin -------------------------------------------------------------------------------- /assets/models/binaries/plane.js: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "metadata" : 4 | { 5 | "formatVersion" : 3.1, 6 | "sourceFile" : "plane.obj", 7 | "generatedBy" : "OBJConverter", 8 | "vertices" : 866, 9 | "faces" : 1607, 10 | "normals" : 0, 11 | "uvs" : 0, 12 | "materials" : 0 13 | }, 14 | 15 | "materials": [ { 16 | "DbgColor" : 15658734, 17 | "DbgIndex" : 0, 18 | "DbgName" : "default" 19 | }], 20 | 21 | "buffers": "plane.bin" 22 | 23 | } 24 | -------------------------------------------------------------------------------- /assets/models/binaries/spider.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/models/binaries/spider.bin -------------------------------------------------------------------------------- /assets/models/binaries/spider.js: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "metadata" : 4 | { 5 | "formatVersion" : 3.1, 6 | "sourceFile" : "spider.obj", 7 | "generatedBy" : "OBJConverter", 8 | "vertices" : 1393, 9 | "faces" : 2782, 10 | "normals" : 0, 11 | "uvs" : 0, 12 | "materials" : 0 13 | }, 14 | 15 | "materials": [ { 16 | "DbgColor" : 15658734, 17 | "DbgIndex" : 0, 18 | "DbgName" : "default" 19 | }], 20 | 21 | "buffers": "spider.bin" 22 | 23 | } 24 | -------------------------------------------------------------------------------- /assets/models/binaries/suzanne.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/models/binaries/suzanne.bin -------------------------------------------------------------------------------- /assets/models/binaries/suzanne.js: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "metadata" : 4 | { 5 | "formatVersion" : 3.1, 6 | "sourceFile" : "suzanne_skeleton.obj", 7 | "generatedBy" : "OBJConverter", 8 | "vertices" : 13270, 9 | "faces" : 26832, 10 | "normals" : 13270, 11 | "uvs" : 0, 12 | "materials" : 0 13 | }, 14 | 15 | "materials": [ { 16 | "DbgColor" : 15658734, 17 | "DbgIndex" : 0, 18 | "DbgName" : "default" 19 | }], 20 | 21 | "buffers": "suzanne.bin" 22 | 23 | } 24 | -------------------------------------------------------------------------------- /assets/models/binaries/suzanne_invert.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/models/binaries/suzanne_invert.bin -------------------------------------------------------------------------------- /assets/models/binaries/suzanne_invert.js: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "metadata" : 4 | { 5 | "formatVersion" : 3.1, 6 | "sourceFile" : "suzanne_invert.obj", 7 | "generatedBy" : "OBJConverter", 8 | "vertices" : 1070, 9 | "faces" : 912, 10 | "normals" : 0, 11 | "uvs" : 0, 12 | "materials" : 0 13 | }, 14 | 15 | "materials": [ { 16 | "DbgColor" : 15658734, 17 | "DbgIndex" : 0, 18 | "DbgName" : "default" 19 | }], 20 | 21 | "buffers": "suzanne_invert.bin" 22 | 23 | } 24 | -------------------------------------------------------------------------------- /assets/normals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/normals.png -------------------------------------------------------------------------------- /assets/source/BK_WIDOW/BK_WIDOW.3DS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/source/BK_WIDOW/BK_WIDOW.3DS -------------------------------------------------------------------------------- /assets/source/BK_WIDOW/BK_WIDOW.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/source/BK_WIDOW/BK_WIDOW.JPG -------------------------------------------------------------------------------- /assets/source/BK_WIDOW/BK_WIDOW.LWO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/source/BK_WIDOW/BK_WIDOW.LWO -------------------------------------------------------------------------------- /assets/source/BK_WIDOW/BK_WIDOW.MTL: -------------------------------------------------------------------------------- 1 | # Wavefront material library 2 | # Tue Aug 03 08:00:08 1999 3 | # Created with Viewpoint Interchange www.viewpoint.com 4 | 5 | newmtl blkw_body 6 | Ka 0 0 0 7 | Kd 0 0 0 8 | Ks 0 0 0 9 | illum 2 10 | map_Kd images\bk_widow.tif 11 | -------------------------------------------------------------------------------- /assets/source/BK_WIDOW/BK_WIDOW.TIF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/source/BK_WIDOW/BK_WIDOW.TIF -------------------------------------------------------------------------------- /assets/source/chthulu.max: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/source/chthulu.max -------------------------------------------------------------------------------- /assets/source/skeleton.max: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/source/skeleton.max -------------------------------------------------------------------------------- /assets/source/skeleton/skeleton.3DS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/source/skeleton/skeleton.3DS -------------------------------------------------------------------------------- /assets/source/skeleton/skeleton.max: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/source/skeleton/skeleton.max -------------------------------------------------------------------------------- /assets/source/skeleton/skeleton.mtl: -------------------------------------------------------------------------------- 1 | # 2 | # Wavefront material file 3 | # Converted by the DEEP Exploration Deep Exploration 5.5 5.5.3.2642 Release 4 | # Right Hemisphere, LTD 5 | # http://www.righthemisphere.com/ 6 | # 7 | 8 | newmtl Bones___Vray 9 | Ka 0 0 0 10 | Kd 0.584314 0.584314 0.584314 11 | Ks 0 0 0 12 | illum 2 13 | Ns 9.84916 14 | map_Kd 15 | map_bump 16 | bump 17 | map_opacity 18 | map_d 19 | refl 20 | map_kS 21 | map_kA 22 | map_Ns 23 | 24 | newmtl White___Vray 25 | Ka 0 0 0 26 | Kd 0.584314 0.584314 0.584314 27 | Ks 0 0 0 28 | illum 2 29 | Ns 9.84916 30 | map_Kd 31 | map_bump 32 | bump 33 | map_opacity 34 | map_d 35 | refl 36 | map_kS 37 | map_kA 38 | map_Ns 39 | 40 | newmtl Brown___Vray 41 | Ka 0 0 0 42 | Kd 0.584314 0.584314 0.584314 43 | Ks 0 0 0 44 | illum 2 45 | Ns 9.84916 46 | map_Kd 47 | map_bump 48 | bump 49 | map_opacity 50 | map_d 51 | refl 52 | map_kS 53 | map_kA 54 | map_Ns 55 | 56 | newmtl Explorer_Default 57 | Ka 0.117647 0.117647 0.117647 58 | Kd 0.752941 0.752941 0.752941 59 | Ks 0.752941 0.752941 0.752941 60 | illum 2 61 | Ns 8 62 | map_Kd 63 | map_bump 64 | bump 65 | map_opacity 66 | map_d 67 | refl 68 | map_kS 69 | map_kA 70 | map_Ns 71 | -------------------------------------------------------------------------------- /assets/source/skull.max: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/source/skull.max -------------------------------------------------------------------------------- /assets/source/spider.max: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/source/spider.max -------------------------------------------------------------------------------- /assets/source/suzanne.max: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/source/suzanne.max -------------------------------------------------------------------------------- /assets/textures/matcap/00ZBrush_RedWax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/00ZBrush_RedWax.png -------------------------------------------------------------------------------- /assets/textures/matcap/BazC_SkinMat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/BazC_SkinMat.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/JGSpecial_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/JGSpecial_01.png -------------------------------------------------------------------------------- /assets/textures/matcap/JG_Drink01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/JG_Drink01.png -------------------------------------------------------------------------------- /assets/textures/matcap/JG_Gold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/JG_Gold.png -------------------------------------------------------------------------------- /assets/textures/matcap/JG_Red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/JG_Red.png -------------------------------------------------------------------------------- /assets/textures/matcap/chrome_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/chrome_dark.png -------------------------------------------------------------------------------- /assets/textures/matcap/chrome_eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/chrome_eye.png -------------------------------------------------------------------------------- /assets/textures/matcap/close_to_50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/close_to_50.png -------------------------------------------------------------------------------- /assets/textures/matcap/darker.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/darker.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/droplet_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/droplet_01.png -------------------------------------------------------------------------------- /assets/textures/matcap/env.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/env.png -------------------------------------------------------------------------------- /assets/textures/matcap/generator1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/generator1.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/generator3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/generator3.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/generator5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/generator5.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/generator6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/generator6.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/generator7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/generator7.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/generator8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/generator8.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/generator9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/generator9.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/genetic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/genetic.png -------------------------------------------------------------------------------- /assets/textures/matcap/ghost.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/ghost.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/gold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/gold.png -------------------------------------------------------------------------------- /assets/textures/matcap/green_gel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/green_gel.png -------------------------------------------------------------------------------- /assets/textures/matcap/grey_reflective.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/grey_reflective.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/index.json: -------------------------------------------------------------------------------- 1 | [ 2 | "00ZBrush_RedWax.png", 3 | "close_to_50.png", 4 | "droplet_01.png", 5 | "green_gel.png", 6 | "JGSpecial_01.png", 7 | "JG_Drink01.png", 8 | "JG_Gold.png", 9 | "JG_Red.png", 10 | "mashrim.png", 11 | "material2.png", 12 | "material4.png", 13 | "softunderlight.png", 14 | "strong rim.png", 15 | "BazC_SkinMat.jpg", 16 | "darker.jpg", 17 | "generator1.jpg", 18 | "generator3.jpg", 19 | "generator5.jpg", 20 | "generator6.jpg", 21 | "generator7.jpg", 22 | "generator8.jpg", 23 | "generator9.jpg", 24 | "ghost.jpg", 25 | "grey_reflective.jpg", 26 | "mashrim2.jpg", 27 | "material3.jpg", 28 | "mshade3.jpg", 29 | "mshade4.jpg", 30 | "mshade5.jpg", 31 | "normals.jpg", 32 | "red_bob.jpg", 33 | "red_clay.jpg", 34 | "right_light.jpg", 35 | "scary-light.jpg", 36 | "silver.jpg", 37 | "skintone.jpg", 38 | "test_gold.jpg", 39 | "test_steel.jpg", 40 | "thuglee-03.jpg", 41 | "thuglee-backlight-01.jpg", 42 | "thuglee-chrome-02b.jpg", 43 | "untitled.6.jpg" 44 | ] -------------------------------------------------------------------------------- /assets/textures/matcap/mashrim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/mashrim.png -------------------------------------------------------------------------------- /assets/textures/matcap/mashrim2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/mashrim2.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/matcap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/matcap.png -------------------------------------------------------------------------------- /assets/textures/matcap/material2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/material2.png -------------------------------------------------------------------------------- /assets/textures/matcap/material3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/material3.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/material4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/material4.png -------------------------------------------------------------------------------- /assets/textures/matcap/mshade3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/mshade3.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/mshade4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/mshade4.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/mshade5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/mshade5.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/normals.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/normals.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/old_gold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/old_gold.png -------------------------------------------------------------------------------- /assets/textures/matcap/red_bob.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/red_bob.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/red_clay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/red_clay.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/right_light.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/right_light.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/scary-light.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/scary-light.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/silver.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/silver.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/skintone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/skintone.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/softunderlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/softunderlight.png -------------------------------------------------------------------------------- /assets/textures/matcap/strong rim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/strong rim.png -------------------------------------------------------------------------------- /assets/textures/matcap/test_gold.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/test_gold.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/test_steel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/test_steel.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/thuggle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/thuggle.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/thuglee-03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/thuglee-03.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/thuglee-backlight-01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/thuglee-backlight-01.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/thuglee-chrome-02b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/thuglee-chrome-02b.jpg -------------------------------------------------------------------------------- /assets/textures/matcap/untitled.6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/matcap/untitled.6.jpg -------------------------------------------------------------------------------- /assets/textures/particles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/textures/particles.png -------------------------------------------------------------------------------- /assets/valid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/assets/valid.png -------------------------------------------------------------------------------- /dwarf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | THREE.MeshLine - Shape example 6 | 7 | 8 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /glsl/env_fs.glsl: -------------------------------------------------------------------------------- 1 | 2 | uniform vec3 bottomColor; 3 | uniform vec3 topColor; 4 | uniform float horizon; 5 | uniform float spread; 6 | varying float vY; 7 | void main() 8 | { 9 | 10 | float val = smoothstep( horizon-spread, horizon+spread, vY ); 11 | gl_FragColor = vec4( mix( bottomColor, topColor, val ), 1. ); 12 | 13 | 14 | } -------------------------------------------------------------------------------- /glsl/env_vs.glsl: -------------------------------------------------------------------------------- 1 | varying float vY; 2 | void main() { 3 | 4 | vY = position.y + .5; 5 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); 6 | 7 | 8 | } -------------------------------------------------------------------------------- /glsl/line_sem_fs.glsl: -------------------------------------------------------------------------------- 1 | uniform sampler2D tMatCap; 2 | uniform float alpha; 3 | 4 | varying vec3 e; 5 | varying vec3 n; 6 | 7 | void main() { 8 | 9 | vec3 r = reflect( e, n ); 10 | float m = 2. * sqrt( pow( r.x, 2. ) + pow( r.y, 2. ) + pow( r.z + 1., 2. ) ); 11 | vec2 vN = r.xy / m + .5; 12 | vec3 base = texture2D( tMatCap, vN ).rgb; 13 | gl_FragColor = vec4( base, alpha ); 14 | 15 | } -------------------------------------------------------------------------------- /glsl/line_sem_vs.glsl: -------------------------------------------------------------------------------- 1 | 2 | float SimplexPerlin3D( vec3 P ) 3 | { 4 | // https://github.com/BrianSharpe/Wombat/blob/master/SimplexPerlin3D.glsl 5 | 6 | // simplex math constants 7 | const float SKEWFACTOR = 1.0/3.0; 8 | const float UNSKEWFACTOR = 1.0/6.0; 9 | const float SIMPLEX_CORNER_POS = 0.5; 10 | const float SIMPLEX_TETRAHADRON_HEIGHT = 0.70710678118654752440084436210485; // sqrt( 0.5 ) 11 | 12 | // establish our grid cell. 13 | P *= SIMPLEX_TETRAHADRON_HEIGHT; // scale space so we can have an approx feature size of 1.0 14 | vec3 Pi = floor( P + dot( P, vec3( SKEWFACTOR) ) ); 15 | 16 | // Find the vectors to the corners of our simplex tetrahedron 17 | vec3 x0 = P - Pi + dot(Pi, vec3( UNSKEWFACTOR ) ); 18 | vec3 g = step(x0.yzx, x0.xyz); 19 | vec3 l = 1.0 - g; 20 | vec3 Pi_1 = min( g.xyz, l.zxy ); 21 | vec3 Pi_2 = max( g.xyz, l.zxy ); 22 | vec3 x1 = x0 - Pi_1 + UNSKEWFACTOR; 23 | vec3 x2 = x0 - Pi_2 + SKEWFACTOR; 24 | vec3 x3 = x0 - SIMPLEX_CORNER_POS; 25 | 26 | // pack them into a parallel-friendly arrangement 27 | vec4 v1234_x = vec4( x0.x, x1.x, x2.x, x3.x ); 28 | vec4 v1234_y = vec4( x0.y, x1.y, x2.y, x3.y ); 29 | vec4 v1234_z = vec4( x0.z, x1.z, x2.z, x3.z ); 30 | 31 | // clamp the domain of our grid cell 32 | Pi.xyz = Pi.xyz - floor(Pi.xyz * ( 1.0 / 69.0 )) * 69.0; 33 | vec3 Pi_inc1 = step( Pi, vec3( 69.0 - 1.5 ) ) * ( Pi + 1.0 ); 34 | 35 | // generate the random vectors 36 | vec4 Pt = vec4( Pi.xy, Pi_inc1.xy ) + vec2( 50.0, 161.0 ).xyxy; 37 | Pt *= Pt; 38 | vec4 V1xy_V2xy = mix( Pt.xyxy, Pt.zwzw, vec4( Pi_1.xy, Pi_2.xy ) ); 39 | Pt = vec4( Pt.x, V1xy_V2xy.xz, Pt.z ) * vec4( Pt.y, V1xy_V2xy.yw, Pt.w ); 40 | const vec3 SOMELARGEFLOATS = vec3( 635.298681, 682.357502, 668.926525 ); 41 | const vec3 ZINC = vec3( 48.500388, 65.294118, 63.934599 ); 42 | vec3 lowz_mods = vec3( 1.0 / ( SOMELARGEFLOATS.xyz + Pi.zzz * ZINC.xyz ) ); 43 | vec3 highz_mods = vec3( 1.0 / ( SOMELARGEFLOATS.xyz + Pi_inc1.zzz * ZINC.xyz ) ); 44 | Pi_1 = ( Pi_1.z < 0.5 ) ? lowz_mods : highz_mods; 45 | Pi_2 = ( Pi_2.z < 0.5 ) ? lowz_mods : highz_mods; 46 | vec4 hash_0 = fract( Pt * vec4( lowz_mods.x, Pi_1.x, Pi_2.x, highz_mods.x ) ) - 0.49999; 47 | vec4 hash_1 = fract( Pt * vec4( lowz_mods.y, Pi_1.y, Pi_2.y, highz_mods.y ) ) - 0.49999; 48 | vec4 hash_2 = fract( Pt * vec4( lowz_mods.z, Pi_1.z, Pi_2.z, highz_mods.z ) ) - 0.49999; 49 | 50 | // evaluate gradients 51 | vec4 grad_results = inversesqrt( hash_0 * hash_0 + hash_1 * hash_1 + hash_2 * hash_2 ) * ( hash_0 * v1234_x + hash_1 * v1234_y + hash_2 * v1234_z ); 52 | 53 | // Normalization factor to scale the final result to a strict 1.0->-1.0 range 54 | // http://briansharpe.wordpress.com/2012/01/13/simplex-noise/#comment-36 55 | const float FINAL_NORMALIZATION = 37.837227241611314102871574478976; 56 | 57 | // evaulate the kernel weights ( use (0.5-x*x)^3 instead of (0.6-x*x)^4 to fix discontinuities ) 58 | vec4 kernel_weights = v1234_x * v1234_x + v1234_y * v1234_y + v1234_z * v1234_z; 59 | kernel_weights = max(0.5 - kernel_weights, 0.0); 60 | kernel_weights = kernel_weights*kernel_weights*kernel_weights; 61 | 62 | // sum with the kernel and return 63 | return dot( kernel_weights, grad_results ) * FINAL_NORMALIZATION; 64 | } 65 | uniform float time; 66 | varying vec3 e; 67 | varying vec3 n; 68 | 69 | void main() { 70 | 71 | vec3 t = vec3( 0, cos( time * .1 ), time * .1 ); 72 | 73 | e = normalize( vec3( modelViewMatrix * vec4( position, 1.0 ) ) ); 74 | n = normalize( ( modelViewMatrix * vec4( position, 1. ) ).xyz ); 75 | 76 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1. ); 77 | 78 | } -------------------------------------------------------------------------------- /glsl/meshline_fs.glsl: -------------------------------------------------------------------------------- 1 | #extension GL_OES_standard_derivatives : enable 2 | precision mediump float; 3 | 4 | uniform sampler2D map; 5 | uniform sampler2D alphaMap; 6 | uniform float useMap; 7 | uniform float useAlphaMap; 8 | uniform float useDash; 9 | uniform vec2 dashArray; 10 | uniform vec2 visibility; 11 | uniform vec2 depth; 12 | uniform float alphaTest; 13 | uniform vec2 repeat; 14 | 15 | varying vec2 vUV; 16 | varying vec4 vColor; 17 | varying float vCounters; 18 | varying float vZ; 19 | 20 | void main() { 21 | 22 | vec4 c = vColor; 23 | if( useMap == 1. ) c *= texture2D( map, vUV * repeat ); 24 | if( useAlphaMap == 1. ) c.a *= texture2D( alphaMap, vUV * repeat ).a; 25 | if( c.a < alphaTest ) discard; 26 | if( useDash == 1. ){ 27 | 28 | } 29 | gl_FragColor = c; 30 | 31 | float alpha = abs( sin( smoothstep(visibility.x, visibility.y, vCounters) * 3.14159 ) ); 32 | gl_FragColor.rgb *= pow( alpha,.5 ); 33 | gl_FragColor.a *= step(visibility.x, vCounters) * step(vCounters,visibility.y) * alpha; 34 | } -------------------------------------------------------------------------------- /glsl/meshline_vs.glsl: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | attribute vec3 position; 4 | attribute vec3 previous; 5 | attribute vec3 next; 6 | attribute float side; 7 | attribute float width; 8 | attribute vec2 uv; 9 | attribute float counters; 10 | 11 | uniform mat4 projectionMatrix; 12 | uniform mat4 modelViewMatrix; 13 | uniform vec2 resolution; 14 | uniform float lineWidth; 15 | uniform vec3 color; 16 | uniform float opacity; 17 | uniform float near; 18 | uniform float far; 19 | uniform float sizeAttenuation; 20 | uniform float time; 21 | 22 | varying vec2 vUV; 23 | varying vec4 vColor; 24 | varying float vCounters; 25 | varying float vZ; 26 | 27 | float SimplexPerlin3D( vec3 P ) 28 | { 29 | // https://github.com/BrianSharpe/Wombat/blob/master/SimplexPerlin3D.glsl 30 | 31 | // simplex math constants 32 | const float SKEWFACTOR = 1.0/3.0; 33 | const float UNSKEWFACTOR = 1.0/6.0; 34 | const float SIMPLEX_CORNER_POS = 0.5; 35 | const float SIMPLEX_TETRAHADRON_HEIGHT = 0.70710678118654752440084436210485; // sqrt( 0.5 ) 36 | 37 | // establish our grid cell. 38 | P *= SIMPLEX_TETRAHADRON_HEIGHT; // scale space so we can have an approx feature size of 1.0 39 | vec3 Pi = floor( P + dot( P, vec3( SKEWFACTOR) ) ); 40 | 41 | // Find the vectors to the corners of our simplex tetrahedron 42 | vec3 x0 = P - Pi + dot(Pi, vec3( UNSKEWFACTOR ) ); 43 | vec3 g = step(x0.yzx, x0.xyz); 44 | vec3 l = 1.0 - g; 45 | vec3 Pi_1 = min( g.xyz, l.zxy ); 46 | vec3 Pi_2 = max( g.xyz, l.zxy ); 47 | vec3 x1 = x0 - Pi_1 + UNSKEWFACTOR; 48 | vec3 x2 = x0 - Pi_2 + SKEWFACTOR; 49 | vec3 x3 = x0 - SIMPLEX_CORNER_POS; 50 | 51 | // pack them into a parallel-friendly arrangement 52 | vec4 v1234_x = vec4( x0.x, x1.x, x2.x, x3.x ); 53 | vec4 v1234_y = vec4( x0.y, x1.y, x2.y, x3.y ); 54 | vec4 v1234_z = vec4( x0.z, x1.z, x2.z, x3.z ); 55 | 56 | // clamp the domain of our grid cell 57 | Pi.xyz = Pi.xyz - floor(Pi.xyz * ( 1.0 / 69.0 )) * 69.0; 58 | vec3 Pi_inc1 = step( Pi, vec3( 69.0 - 1.5 ) ) * ( Pi + 1.0 ); 59 | 60 | // generate the random vectors 61 | vec4 Pt = vec4( Pi.xy, Pi_inc1.xy ) + vec2( 50.0, 161.0 ).xyxy; 62 | Pt *= Pt; 63 | vec4 V1xy_V2xy = mix( Pt.xyxy, Pt.zwzw, vec4( Pi_1.xy, Pi_2.xy ) ); 64 | Pt = vec4( Pt.x, V1xy_V2xy.xz, Pt.z ) * vec4( Pt.y, V1xy_V2xy.yw, Pt.w ); 65 | const vec3 SOMELARGEFLOATS = vec3( 635.298681, 682.357502, 668.926525 ); 66 | const vec3 ZINC = vec3( 48.500388, 65.294118, 63.934599 ); 67 | vec3 lowz_mods = vec3( 1.0 / ( SOMELARGEFLOATS.xyz + Pi.zzz * ZINC.xyz ) ); 68 | vec3 highz_mods = vec3( 1.0 / ( SOMELARGEFLOATS.xyz + Pi_inc1.zzz * ZINC.xyz ) ); 69 | Pi_1 = ( Pi_1.z < 0.5 ) ? lowz_mods : highz_mods; 70 | Pi_2 = ( Pi_2.z < 0.5 ) ? lowz_mods : highz_mods; 71 | vec4 hash_0 = fract( Pt * vec4( lowz_mods.x, Pi_1.x, Pi_2.x, highz_mods.x ) ) - 0.49999; 72 | vec4 hash_1 = fract( Pt * vec4( lowz_mods.y, Pi_1.y, Pi_2.y, highz_mods.y ) ) - 0.49999; 73 | vec4 hash_2 = fract( Pt * vec4( lowz_mods.z, Pi_1.z, Pi_2.z, highz_mods.z ) ) - 0.49999; 74 | 75 | // evaluate gradients 76 | vec4 grad_results = inversesqrt( hash_0 * hash_0 + hash_1 * hash_1 + hash_2 * hash_2 ) * ( hash_0 * v1234_x + hash_1 * v1234_y + hash_2 * v1234_z ); 77 | 78 | // Normalization factor to scale the final result to a strict 1.0->-1.0 range 79 | // http://briansharpe.wordpress.com/2012/01/13/simplex-noise/#comment-36 80 | const float FINAL_NORMALIZATION = 37.837227241611314102871574478976; 81 | 82 | // evaulate the kernel weights ( use (0.5-x*x)^3 instead of (0.6-x*x)^4 to fix discontinuities ) 83 | vec4 kernel_weights = v1234_x * v1234_x + v1234_y * v1234_y + v1234_z * v1234_z; 84 | kernel_weights = max(0.5 - kernel_weights, 0.0); 85 | kernel_weights = kernel_weights*kernel_weights*kernel_weights; 86 | 87 | // sum with the kernel and return 88 | return dot( kernel_weights, grad_results ) * FINAL_NORMALIZATION; 89 | } 90 | vec2 fix( vec4 i, float aspect ) { 91 | 92 | vec2 res = i.xy / i.w; 93 | res.x *= aspect; 94 | vCounters = counters; 95 | return res; 96 | 97 | } 98 | 99 | void main() { 100 | 101 | float aspect = resolution.x / resolution.y; 102 | float pixelWidthRatio = 1. / (resolution.x * projectionMatrix[0][0]); 103 | 104 | vColor = vec4( color, opacity ); 105 | vUV = uv; 106 | 107 | vec3 t = vec3( 0, cos( time * .1 ), time * .1 ); 108 | vec3 pos = position + SimplexPerlin3D( position * 0.01 + t * 5. ) * .5; 109 | vZ = pos.z; 110 | 111 | mat4 m = projectionMatrix * modelViewMatrix; 112 | vec4 finalPosition = m * vec4( pos, 1.0 ); 113 | vec4 prevPos = m * vec4( previous, 1.0 ); 114 | vec4 nextPos = m * vec4( next, 1.0 ); 115 | 116 | vec2 currentP = fix( finalPosition, aspect ); 117 | vec2 prevP = fix( prevPos, aspect ); 118 | vec2 nextP = fix( nextPos, aspect ); 119 | 120 | float pixelWidth = finalPosition.w * pixelWidthRatio; 121 | float w = 1.8 * pixelWidth * lineWidth * width; 122 | 123 | if( sizeAttenuation == 1. ) { 124 | w = 1.8 * lineWidth * width; 125 | } 126 | 127 | vec2 dir; 128 | if( nextP == currentP ) dir = normalize( currentP - prevP ); 129 | else if( prevP == currentP ) dir = normalize( nextP - currentP ); 130 | else { 131 | vec2 dir1 = normalize( currentP - prevP ); 132 | vec2 dir2 = normalize( nextP - currentP ); 133 | dir = normalize( dir1 + dir2 ); 134 | 135 | vec2 perp = vec2( -dir1.y, dir1.x ); 136 | vec2 miter = vec2( -dir.y, dir.x ); 137 | //w = clamp( w / dot( miter, perp ), 0., 4. * lineWidth * width ); 138 | 139 | } 140 | 141 | //vec2 normal = ( cross( vec3( dir, 0. ), vec3( 0., 0., 1. ) ) ).xy; 142 | vec2 normal = vec2( -dir.y, dir.x ); 143 | normal.x /= aspect; 144 | normal *= .5 * w; 145 | 146 | vec4 offset = vec4( normal * side, 0.0, 1.0 ); 147 | finalPosition.xy += offset.xy; 148 | 149 | gl_Position = finalPosition; 150 | 151 | } -------------------------------------------------------------------------------- /glsl/particles_fs.glsl: -------------------------------------------------------------------------------- 1 | uniform vec3 color0; 2 | uniform vec3 color1; 3 | varying float vAlpha; 4 | 5 | void main(){ 6 | vec3 color = mix( color0, color1, vAlpha ); 7 | gl_FragColor = vec4( color, pow( vAlpha, .5 ) ); 8 | } -------------------------------------------------------------------------------- /glsl/particles_vs.glsl: -------------------------------------------------------------------------------- 1 | attribute vec3 dest; 2 | 3 | uniform vec2 bounds; 4 | uniform float time; 5 | uniform float modBig; 6 | uniform float pointSize; 7 | uniform float alpha; 8 | 9 | vec3 mod289(vec3 x) { 10 | return x - floor(x * (1.0 / 289.0)) * 289.0; 11 | } 12 | 13 | vec2 mod289(vec2 x) { 14 | return x - floor(x * (1.0 / 289.0)) * 289.0; 15 | } 16 | 17 | vec3 permute(vec3 x) { 18 | return mod289(((x*34.0)+1.0)*x); 19 | } 20 | 21 | float noise(vec2 v) 22 | { 23 | const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 24 | 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) 25 | -0.577350269189626, // -1.0 + 2.0 * C.x 26 | 0.024390243902439); // 1.0 / 41.0 27 | // First corner 28 | vec2 i = floor(v + dot(v, C.yy) ); 29 | vec2 x0 = v - i + dot(i, C.xx); 30 | 31 | // Other corners 32 | vec2 i1; 33 | //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 34 | //i1.y = 1.0 - i1.x; 35 | i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); 36 | // x0 = x0 - 0.0 + 0.0 * C.xx ; 37 | // x1 = x0 - i1 + 1.0 * C.xx ; 38 | // x2 = x0 - 1.0 + 2.0 * C.xx ; 39 | vec4 x12 = x0.xyxy + C.xxzz; 40 | x12.xy -= i1; 41 | 42 | // Permutations 43 | i = mod289(i); // Avoid truncation effects in permutation 44 | vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) 45 | + i.x + vec3(0.0, i1.x, 1.0 )); 46 | 47 | vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); 48 | m = m*m ; 49 | m = m*m ; 50 | 51 | // Gradients: 41 points uniformly over a line, mapped onto a diamond. 52 | // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) 53 | 54 | vec3 x = 2.0 * fract(p * C.www) - 1.0; 55 | vec3 h = abs(x) - 0.5; 56 | vec3 ox = floor(x + 0.5); 57 | vec3 a0 = x - ox; 58 | 59 | // Normalise gradients implicitly by scaling m 60 | // Approximation of: m *= inversesqrt( a0*a0 + h*h ); 61 | m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); 62 | 63 | // Compute final noise value at P 64 | vec3 g; 65 | g.x = a0.x * x0.x + h.x * x0.y; 66 | g.yz = a0.yz * x12.xz + h.yz * x12.yw; 67 | return 130.0 * dot(m, g); 68 | } 69 | 70 | varying float vAlpha; 71 | void main() { 72 | 73 | float t = time; 74 | float a = alpha; 75 | 76 | a = smoothstep( -1.,1., noise( vec2( position.x * position.y + time * 2. , time * .5 ) * .1 ) ); 77 | a = bounds.x + a * bounds.y; 78 | vec3 pos = mix( position, dest, a ); 79 | 80 | vAlpha = max( .25, a ); 81 | 82 | float N1 = modBig; 83 | float P1 = step(mod( floor( position.x * N1 ), N1 ), 1. ); 84 | gl_PointSize = 2. + ( pointSize * P1 ); 85 | 86 | gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1.0 ); 87 | 88 | 89 | } -------------------------------------------------------------------------------- /glsl/sem_fs.glsl: -------------------------------------------------------------------------------- 1 | uniform sampler2D tMatCap; 2 | uniform float alpha; 3 | 4 | varying vec3 e; 5 | varying vec3 n; 6 | 7 | void main() { 8 | 9 | vec3 r = reflect( e, n ); 10 | float m = 2. * sqrt( pow( r.x, 2. ) + pow( r.y, 2. ) + pow( r.z + 1., 2. ) ); 11 | vec2 vN = r.xy / m + .5; 12 | 13 | vec3 base = texture2D( tMatCap, vN ).rgb; 14 | 15 | gl_FragColor = vec4( base, alpha ); 16 | 17 | } -------------------------------------------------------------------------------- /glsl/sem_vs.glsl: -------------------------------------------------------------------------------- 1 | 2 | float SimplexPerlin3D( vec3 P ) 3 | { 4 | // https://github.com/BrianSharpe/Wombat/blob/master/SimplexPerlin3D.glsl 5 | 6 | // simplex math constants 7 | const float SKEWFACTOR = 1.0/3.0; 8 | const float UNSKEWFACTOR = 1.0/6.0; 9 | const float SIMPLEX_CORNER_POS = 0.5; 10 | const float SIMPLEX_TETRAHADRON_HEIGHT = 0.70710678118654752440084436210485; // sqrt( 0.5 ) 11 | 12 | // establish our grid cell. 13 | P *= SIMPLEX_TETRAHADRON_HEIGHT; // scale space so we can have an approx feature size of 1.0 14 | vec3 Pi = floor( P + dot( P, vec3( SKEWFACTOR) ) ); 15 | 16 | // Find the vectors to the corners of our simplex tetrahedron 17 | vec3 x0 = P - Pi + dot(Pi, vec3( UNSKEWFACTOR ) ); 18 | vec3 g = step(x0.yzx, x0.xyz); 19 | vec3 l = 1.0 - g; 20 | vec3 Pi_1 = min( g.xyz, l.zxy ); 21 | vec3 Pi_2 = max( g.xyz, l.zxy ); 22 | vec3 x1 = x0 - Pi_1 + UNSKEWFACTOR; 23 | vec3 x2 = x0 - Pi_2 + SKEWFACTOR; 24 | vec3 x3 = x0 - SIMPLEX_CORNER_POS; 25 | 26 | // pack them into a parallel-friendly arrangement 27 | vec4 v1234_x = vec4( x0.x, x1.x, x2.x, x3.x ); 28 | vec4 v1234_y = vec4( x0.y, x1.y, x2.y, x3.y ); 29 | vec4 v1234_z = vec4( x0.z, x1.z, x2.z, x3.z ); 30 | 31 | // clamp the domain of our grid cell 32 | Pi.xyz = Pi.xyz - floor(Pi.xyz * ( 1.0 / 69.0 )) * 69.0; 33 | vec3 Pi_inc1 = step( Pi, vec3( 69.0 - 1.5 ) ) * ( Pi + 1.0 ); 34 | 35 | // generate the random vectors 36 | vec4 Pt = vec4( Pi.xy, Pi_inc1.xy ) + vec2( 50.0, 161.0 ).xyxy; 37 | Pt *= Pt; 38 | vec4 V1xy_V2xy = mix( Pt.xyxy, Pt.zwzw, vec4( Pi_1.xy, Pi_2.xy ) ); 39 | Pt = vec4( Pt.x, V1xy_V2xy.xz, Pt.z ) * vec4( Pt.y, V1xy_V2xy.yw, Pt.w ); 40 | const vec3 SOMELARGEFLOATS = vec3( 635.298681, 682.357502, 668.926525 ); 41 | const vec3 ZINC = vec3( 48.500388, 65.294118, 63.934599 ); 42 | vec3 lowz_mods = vec3( 1.0 / ( SOMELARGEFLOATS.xyz + Pi.zzz * ZINC.xyz ) ); 43 | vec3 highz_mods = vec3( 1.0 / ( SOMELARGEFLOATS.xyz + Pi_inc1.zzz * ZINC.xyz ) ); 44 | Pi_1 = ( Pi_1.z < 0.5 ) ? lowz_mods : highz_mods; 45 | Pi_2 = ( Pi_2.z < 0.5 ) ? lowz_mods : highz_mods; 46 | vec4 hash_0 = fract( Pt * vec4( lowz_mods.x, Pi_1.x, Pi_2.x, highz_mods.x ) ) - 0.49999; 47 | vec4 hash_1 = fract( Pt * vec4( lowz_mods.y, Pi_1.y, Pi_2.y, highz_mods.y ) ) - 0.49999; 48 | vec4 hash_2 = fract( Pt * vec4( lowz_mods.z, Pi_1.z, Pi_2.z, highz_mods.z ) ) - 0.49999; 49 | 50 | // evaluate gradients 51 | vec4 grad_results = inversesqrt( hash_0 * hash_0 + hash_1 * hash_1 + hash_2 * hash_2 ) * ( hash_0 * v1234_x + hash_1 * v1234_y + hash_2 * v1234_z ); 52 | 53 | // Normalization factor to scale the final result to a strict 1.0->-1.0 range 54 | // http://briansharpe.wordpress.com/2012/01/13/simplex-noise/#comment-36 55 | const float FINAL_NORMALIZATION = 37.837227241611314102871574478976; 56 | 57 | // evaulate the kernel weights ( use (0.5-x*x)^3 instead of (0.6-x*x)^4 to fix discontinuities ) 58 | vec4 kernel_weights = v1234_x * v1234_x + v1234_y * v1234_y + v1234_z * v1234_z; 59 | kernel_weights = max(0.5 - kernel_weights, 0.0); 60 | kernel_weights = kernel_weights*kernel_weights*kernel_weights; 61 | 62 | // sum with the kernel and return 63 | return dot( kernel_weights, grad_results ) * FINAL_NORMALIZATION; 64 | } 65 | varying vec3 e; 66 | varying vec3 n; 67 | 68 | void main() { 69 | 70 | vec3 pos = position; 71 | 72 | e = normalize( vec3( modelViewMatrix * vec4( pos, 1.0 ) ) ); 73 | n = normalize( normalMatrix * normal ); 74 | 75 | gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1. ); 76 | 77 | } -------------------------------------------------------------------------------- /glsl/texture_particles_fs.glsl: -------------------------------------------------------------------------------- 1 | uniform sampler2D texture; 2 | uniform float time; 3 | varying float vAlpha; 4 | varying vec2 vUv; 5 | 6 | vec4 FAST_32_hash( vec2 gridcell ) 7 | { 8 | // gridcell is assumed to be an integer coordinate 9 | const vec2 OFFSET = vec2( 26.0, 161.0 ); 10 | const float DOMAIN = 71.0; 11 | const float SOMELARGEFLOAT = 951.135664; 12 | vec4 P = vec4( gridcell.xy, gridcell.xy + vec2( 1.,1.) ); 13 | P = P - floor(P * ( 1.0 / DOMAIN )) * DOMAIN; // truncate the domain 14 | P += OFFSET.xyxy; // offset to interesting part of the noise 15 | P *= P; // calculate and return the hash 16 | return fract( P.xzxz * P.yyww * vec4( 1.0 / SOMELARGEFLOAT ) ); 17 | } 18 | void main() 19 | { 20 | 21 | // float t = .5 + .5 * (cos( time ) * sin( time ) ); 22 | // gl_FragColor = vec4( vec3( 1. ), vAlpha ); 23 | 24 | vec2 uvs = vUv + gl_PointCoord.xy * vec2( .25 ); 25 | uvs.y = 1. - uvs.y; 26 | gl_FragColor = vec4( 1. ) * texture2D( texture, uvs ) * vAlpha; 27 | 28 | 29 | } -------------------------------------------------------------------------------- /glsl/texture_particles_vs.glsl: -------------------------------------------------------------------------------- 1 | //attribute float pdistance; 2 | //attribute vec3 pnormal; 3 | attribute vec3 dest; 4 | attribute vec2 uvOffset; 5 | 6 | 7 | uniform float time; 8 | uniform float modBig; 9 | uniform float modSmall; 10 | uniform float pointSize; 11 | uniform float alpha; 12 | 13 | vec3 mod289(vec3 x) { 14 | return x - floor(x * (1.0 / 289.0)) * 289.0; 15 | } 16 | 17 | vec2 mod289(vec2 x) { 18 | return x - floor(x * (1.0 / 289.0)) * 289.0; 19 | } 20 | 21 | vec3 permute(vec3 x) { 22 | return mod289(((x*34.0)+1.0)*x); 23 | } 24 | 25 | float noise(vec2 v) 26 | { 27 | const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 28 | 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) 29 | -0.577350269189626, // -1.0 + 2.0 * C.x 30 | 0.024390243902439); // 1.0 / 41.0 31 | // First corner 32 | vec2 i = floor(v + dot(v, C.yy) ); 33 | vec2 x0 = v - i + dot(i, C.xx); 34 | 35 | // Other corners 36 | vec2 i1; 37 | //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 38 | //i1.y = 1.0 - i1.x; 39 | i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); 40 | // x0 = x0 - 0.0 + 0.0 * C.xx ; 41 | // x1 = x0 - i1 + 1.0 * C.xx ; 42 | // x2 = x0 - 1.0 + 2.0 * C.xx ; 43 | vec4 x12 = x0.xyxy + C.xxzz; 44 | x12.xy -= i1; 45 | 46 | // Permutations 47 | i = mod289(i); // Avoid truncation effects in permutation 48 | vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) 49 | + i.x + vec3(0.0, i1.x, 1.0 )); 50 | 51 | vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); 52 | m = m*m ; 53 | m = m*m ; 54 | 55 | // Gradients: 41 points uniformly over a line, mapped onto a diamond. 56 | // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) 57 | 58 | vec3 x = 2.0 * fract(p * C.www) - 1.0; 59 | vec3 h = abs(x) - 0.5; 60 | vec3 ox = floor(x + 0.5); 61 | vec3 a0 = x - ox; 62 | 63 | // Normalise gradients implicitly by scaling m 64 | // Approximation of: m *= inversesqrt( a0*a0 + h*h ); 65 | m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); 66 | 67 | // Compute final noise value at P 68 | vec3 g; 69 | g.x = a0.x * x0.x + h.x * x0.y; 70 | g.yz = a0.yz * x12.xz + h.yz * x12.yw; 71 | return 130.0 * dot(m, g); 72 | } 73 | 74 | vec4 FAST_32_hash( vec2 gridcell ) 75 | { 76 | // gridcell is assumed to be an integer coordinate 77 | const vec2 OFFSET = vec2( 26.0, 161.0 ); 78 | const float DOMAIN = 71.0; 79 | const float SOMELARGEFLOAT = 951.135664; 80 | vec4 P = vec4( gridcell.xy, gridcell.xy + vec2( 1.,1.) ); 81 | P = P - floor(P * ( 1.0 / DOMAIN )) * DOMAIN; // truncate the domain 82 | P += OFFSET.xyxy; // offset to interesting part of the noise 83 | P *= P; // calculate and return the hash 84 | return fract( P.xzxz * P.yyww * vec4( 1.0 / SOMELARGEFLOAT ) ); 85 | } 86 | 87 | varying float vAlpha; 88 | varying vec2 vUv; 89 | void main() { 90 | 91 | float t = time; 92 | float a = alpha; 93 | 94 | a = smoothstep( -1.,1., noise( vec2( position.x * position.y + time * 2. , time * .5 ) * .1 ) ); 95 | vec3 pos = mix( position, dest, a ); 96 | 97 | vAlpha = max( .25, a ); 98 | vUv = uvOffset; 99 | 100 | float N1 = modBig; 101 | float P1 = step(mod( floor( position.x * N1 ), N1 ), 1. ); 102 | gl_PointSize = 4. + ( pointSize * P1 ); 103 | 104 | gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1.0 ); 105 | 106 | 107 | } -------------------------------------------------------------------------------- /img/dwarf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/img/dwarf.jpg -------------------------------------------------------------------------------- /img/plane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/img/plane.jpg -------------------------------------------------------------------------------- /img/spider.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/img/spider.jpg -------------------------------------------------------------------------------- /img/suzanne.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/img/suzanne.jpg -------------------------------------------------------------------------------- /img/suzanne_distribution.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/img/suzanne_distribution.jpg -------------------------------------------------------------------------------- /js/common/Scatter.js: -------------------------------------------------------------------------------- 1 | var Scatter = function( scatter ){ 2 | 3 | var raycaster;//THREE.raycaster: used to shoot rays at the mesh 4 | var o;//ray origin 5 | var d;//ray direction 6 | var intersections;//stores the result of the raycasting 7 | var a;//DOM element tag to download the result ( see particlesToString ) 8 | 9 | scatter.distribute = function( mesh, count ) { 10 | 11 | //this will store the results 12 | var coords = []; 13 | var dests = []; 14 | //temporary vars to store the position and destination 15 | var p0, p1; 16 | 17 | //this has an influence as to how the raycasting is performed 18 | var side = mesh.material.side; 19 | mesh.material.side = THREE.DoubleSide; 20 | 21 | //we'll need this (juste to be sure as it's probably done implicitly when we raycast) 22 | mesh.geometry.computeFaceNormals(); 23 | 24 | //this is used to distributte the origins of the rays 25 | mesh.geometry.computeBoundingBox(); 26 | var bbox = mesh.geometry.boundingBox; 27 | 28 | // 'inflates' the box by 10% to prevent colinearity 29 | // or coplanarity of the origin with the mesh 30 | bbox.min.multiplyScalar( 1.1 ); 31 | bbox.max.multiplyScalar( 1.1 ); 32 | 33 | //computes the box' size to compute random points 34 | var size = bbox.max.sub( bbox.min ); 35 | 36 | //to perform raycast 37 | raycaster = raycaster || new THREE.Raycaster(); 38 | o = o || new THREE.Vector3(); 39 | d = d || new THREE.Vector3(); 40 | 41 | for( var i = 0; i < count; i++ ){ 42 | 43 | // randomize the rays origin 44 | o.x = bbox.min.x + Math.random() * size.x; 45 | o.y = bbox.min.y + Math.random() * size.y; 46 | o.z = bbox.min.z + Math.random() * size.z; 47 | 48 | //randomize the ray's direction 49 | d.x = ( Math.random() - .5 ); 50 | d.y = ( Math.random() - .5 ); 51 | d.z = ( Math.random() - .5 ); 52 | d.normalize(); 53 | 54 | //sets the raycaster 55 | raycaster.set( o, d ); 56 | 57 | //shoots the ray 58 | intersections = raycaster.intersectObject( mesh, false ); 59 | 60 | //no result 61 | if( intersections.length == 0 ){ 62 | 63 | //bail out & continue 64 | i--; 65 | 66 | }else{ 67 | 68 | //checks if we meet the conditions: 69 | //the origin must be outside 70 | var valid = intersections.length >= 2 && ( intersections.length % 2 == 0 ); 71 | if (valid) { 72 | 73 | //tests all the intersection pairs 74 | var additions = -1; 75 | for( var j = 0; j < intersections.length; j+= 2 ){ 76 | 77 | // make sure that the origin -> direction vector have the same 78 | // direction as the normal of the face they hit 79 | 80 | //test the direction against the outwards' face's normal 81 | var dp0 = d.dot(intersections[ j + 1 ].face.normal) <= 0; 82 | 83 | //flips the direction to make it 'look at' the origin 84 | d.negate(); 85 | 86 | //test the direction against the inwards' face's normal 87 | var dp1 = d.dot(intersections[ j ].face.normal) <= 0; 88 | 89 | //flips the direction again for the next test 90 | d.negate(); 91 | 92 | // if both vectors pairs head in the same direction 93 | // the point is guarranteed to be inside 94 | if( dp0 || dp1){ 95 | continue; 96 | } 97 | 98 | //adds the points 99 | if( coords.length < count * 3 ){ 100 | console.log("ok") 101 | p0 = intersections[j].point; 102 | coords.push( p0.x, p0.y, p0.z); 103 | p1 = intersections[j+1].point; 104 | dests.push( p1.x, p1.y, p1.z); 105 | additions++; 106 | } 107 | } 108 | //increments the counter by the number of additions 109 | i += additions; 110 | 111 | }else{ 112 | //invalid intersection, try again... 113 | i--; 114 | } 115 | } 116 | } 117 | 118 | //resets the material side 119 | mesh.material.side = side; 120 | return { 121 | pos:coords, 122 | dst:dests 123 | }; 124 | 125 | }; 126 | 127 | 128 | /** 129 | * converts the result of the scatter to a text string 130 | * @param particles coordinates of the points/dest 131 | * @param decimalPrecision floating point precision 132 | * @param name optional: name for the file 133 | */ 134 | scatter.toString = function( particles, decimalPrecision, name ){ 135 | 136 | var precision = decimalPrecision; 137 | if( precision === undefined )precision = 3; 138 | var coords = assetsLoader.particles.pos.map( function( v ){return v.toFixed( precision ); }); 139 | var dests = assetsLoader.particles.dst.map( function( v ){return v.toFixed( precision ); }); 140 | 141 | var count = ( coords.length / 3 ); 142 | var label = ( name || ( "particles_"+ count ) ) +".txt"; 143 | var data = coords.join(',') + "|" + dests.join(',') ; 144 | 145 | var txtData = new Blob([data], { type: 'text/csv' }); 146 | var txtUrl = window.URL.createObjectURL(txtData); 147 | 148 | a = a || document.createElement( "a" ); 149 | a.setAttribute( "href", txtUrl ); 150 | a.setAttribute( "download", label ); 151 | a.innerHTML = label; 152 | 153 | a.style.position = "absolute"; 154 | a.style.padding = a.style.margin = "10px"; 155 | a.style.bottom = "0"; 156 | a.style.left = "0"; 157 | a.style.backgroundColor = "#FFF"; 158 | 159 | document.body.appendChild( a ); 160 | 161 | }; 162 | 163 | return scatter; 164 | }({}); -------------------------------------------------------------------------------- /js/common/assetsLoader.js: -------------------------------------------------------------------------------- 1 | var assetsLoader = function(exports ){ 2 | 3 | var xhr, bl, tl, queue, callback; 4 | exports.IMG = 0; 5 | exports.MOD = 1; 6 | exports.TXT = 2; 7 | exports.load = function( list, cb ){ 8 | 9 | 10 | queue = list; 11 | callback = cb; 12 | 13 | bl = new THREE.BinaryLoader(); 14 | tl = new THREE.TextureLoader(); 15 | xhr = new XMLHttpRequest(); 16 | xhr.onload = onLoad; 17 | 18 | loadNext(); 19 | 20 | }; 21 | 22 | function loadNext(){ 23 | 24 | if( queue.length == 0 ){ 25 | if( callback )callback(); 26 | return; 27 | } 28 | 29 | if( queue[0].type == assetsLoader.IMG ){ 30 | tl.load( queue[0].url, onLoad ); 31 | } 32 | 33 | if( queue[0].type == assetsLoader.MOD ){ 34 | bl.load( queue[0].url, onLoad ); 35 | } 36 | 37 | if( queue[0].type == assetsLoader.TXT ){ 38 | xhr.open( "GET", queue[0].url ); 39 | xhr.send(); 40 | } 41 | 42 | } 43 | 44 | function onLoad( e ){ 45 | 46 | if( queue[0].type == assetsLoader.TXT ){ 47 | exports[ queue[0].name ] = e.target.responseText; 48 | 49 | }else{ 50 | exports[ queue[0].name ] = e; 51 | } 52 | 53 | if( queue[0].onLoad !== undefined ){ 54 | queue[0].onLoad( exports[ queue[0].name ] ); 55 | } 56 | 57 | queue.shift(); 58 | loadNext(); 59 | 60 | } 61 | 62 | return exports; 63 | 64 | }({}); -------------------------------------------------------------------------------- /js/common/scene3d.js: -------------------------------------------------------------------------------- 1 | 2 | var scene, camera, renderer, resolution, controls, materials, startTime, colors; 3 | 4 | function init3D(){ 5 | 6 | scene = new THREE.Scene(); 7 | camera = new THREE.PerspectiveCamera( 42, window.innerWidth / window.innerHeight, 1, 10000 ); 8 | 9 | renderer = new THREE.WebGLRenderer({antialias:true}); 10 | renderer.setClearColor( new THREE.Color( 0x101010 )); 11 | renderer.setSize( window.innerWidth, window.innerHeight ); 12 | renderer.setPixelRatio( window.devicePixelRatio ); 13 | document.body.appendChild( renderer.domElement ); 14 | 15 | controls = new THREE.OrbitControls( camera, renderer.domElement ); 16 | 17 | materials = {}; 18 | startTime = Date.now(); 19 | 20 | colors = "264653-2a9d8f-e9c46a-f4a261-e76f51".split('-').map( function( v ){ return parseInt( "0x" + v ); } ); 21 | colors = colors.concat( "114b5f-456990-028090-79b473-70a37f".split('-').map( function( v ){ return parseInt( "0x" + v ); } ) ); 22 | resolution = new THREE.Vector2( window.innerWidth, window.innerHeight ); 23 | 24 | window.addEventListener( 'resize', onResize ); 25 | onResize(); 26 | 27 | } 28 | 29 | function onResize() { 30 | 31 | var w = window.innerWidth; 32 | var h = window.innerHeight; 33 | camera.aspect = w / h; 34 | camera.updateProjectionMatrix(); 35 | renderer.setSize( w, h ); 36 | resolution.set( w, h ); 37 | 38 | } 39 | //utils 40 | function lerp ( t, a, b ){ return a * (1-t) + b * t; } 41 | // function norm( t, a, b ){return ( t - a ) / ( b - a );} 42 | // function map( t, a0, b0, a1, b1 ){ return lerp( norm( t, a0, b0 ), a1, b1 );} 43 | 44 | -------------------------------------------------------------------------------- /js/dwarf.js: -------------------------------------------------------------------------------- 1 | 2 | var dwarf, env, particles, lines = [], origin; 3 | 4 | var colors = "264653-2a9d8f-e9c46a-f4a261-e76f51".split('-').map( function( v ){ return parseInt( "0x" + v ); } ); 5 | colors = colors.concat( "f2f3ae-edd382-e7a977-e87461-b38cb4".split('-').map( function( v ){ return parseInt( "0x" + v ); } ) ); 6 | colors = colors.concat( "114b5f-456990-028090-79b473-70a37f".split('-').map( function( v ){ return parseInt( "0x" + v ); } ) ); 7 | 8 | 9 | window.onload = function(){ 10 | 11 | var queue = [ 12 | 13 | {name: "meshline_vs", url: "./glsl/meshline_vs.glsl", type:assetsLoader.TXT }, 14 | {name: "meshline_fs", url: "./glsl/meshline_fs.glsl", type:assetsLoader.TXT }, 15 | {name: "sem_vs", url: "./glsl/sem_vs.glsl", type:assetsLoader.TXT }, 16 | {name: "sem_fs", url: "./glsl/sem_fs.glsl", type:assetsLoader.TXT }, 17 | {name: "env_vs", url: "./glsl/env_vs.glsl", type:assetsLoader.TXT }, 18 | {name: "env_fs", url: "./glsl/env_fs.glsl", type:assetsLoader.TXT }, 19 | 20 | { 21 | name: "dwarfTexture", 22 | url: "./assets/textures/matcap/env.png",type:assetsLoader.IMG 23 | }, 24 | { 25 | name: "dwarf", 26 | url: "./assets/models/binaries/dwarf.js",type:assetsLoader.MOD 27 | }, 28 | { 29 | name: "particles", 30 | url:"./assets/models/particles/dwarf/dwarf2k.txt", type:assetsLoader.TXT, 31 | onLoad:function (txt) { 32 | var obj = {}; 33 | var res = txt.split( '|' ); 34 | obj.pos = res[0].split(',').map( function( v ){return parseFloat( v ); } ); 35 | obj.dst = res[1].split(',').map( function( v ){return parseFloat( v ); } ); 36 | assetsLoader.particles = obj; 37 | } 38 | } 39 | ]; 40 | assetsLoader.load(queue, init); 41 | }; 42 | 43 | function init() { 44 | 45 | init3D(); 46 | 47 | camera.position.x = -200; 48 | camera.position.y = 90; 49 | camera.position.z = 300; 50 | 51 | createMaterials(); 52 | createMeshes(); 53 | 54 | render(); 55 | } 56 | 57 | function createMaterials(){ 58 | 59 | startTime = Date.now(); 60 | 61 | materials.dwarf = new THREE.ShaderMaterial({ 62 | uniforms:{ 63 | tMatCap : {type:"t", value:assetsLoader.dwarfTexture }, 64 | time:{type:"f", value:0 }, 65 | alpha:{type:"f", value:.5 } 66 | }, 67 | vertexShader:assetsLoader.sem_vs, 68 | fragmentShader:assetsLoader.sem_fs, 69 | blending:THREE.MultiplyBlending, 70 | transparent: true, 71 | depthWrite:false 72 | }); 73 | 74 | materials.environment = new THREE.ShaderMaterial({ 75 | uniforms : { 76 | horizon:{type:"f", value: .45 }, 77 | spread:{type:"f", value: .05 }, 78 | topColor:{type:"v3", value:new THREE.Color( 0xEEEEEE )}, 79 | bottomColor:{type:"v3", value:new THREE.Color( 0xBBBBBB )} 80 | }, 81 | vertexShader: assetsLoader.env_vs, 82 | fragmentShader: assetsLoader.env_fs, 83 | side:THREE.BackSide, 84 | depthWrite:false 85 | }); 86 | 87 | } 88 | 89 | function createMeshes() { 90 | 91 | assetsLoader.dwarf.computeVertexNormals(); 92 | dwarf = new THREE.Mesh(assetsLoader.dwarf, materials.dwarf ); 93 | scene.add(dwarf); 94 | 95 | env = new THREE.Mesh(new THREE.CylinderBufferGeometry(.5, .5, 1, 64), materials.environment); 96 | env.scale.multiplyScalar(1000); 97 | scene.add(env); 98 | 99 | if( assetsLoader.particles === undefined ){ 100 | 101 | var model = dwarf; 102 | var count = Math.pow( 2, 11 );//->2048 103 | 104 | assetsLoader.particles = Scatter.distribute( model, count ); 105 | Scatter.toString( assetsLoader.particles, 3, "dwarf"+~~(count/1000)+"k" ); 106 | 107 | } 108 | 109 | //create line sets 110 | // colllect vector3 from particle positions 111 | var nodes = []; 112 | var pos = assetsLoader.particles.pos; 113 | var dst = assetsLoader.particles.dst; 114 | for( var i = 0; i< pos.length; i+=3 ){ 115 | 116 | nodes.push( new THREE.Vector3( 117 | (pos[ i ]+dst[i])* .5, 118 | (pos[ i+1 ]+dst[i+1])* .5, 119 | (pos[ i+2 ]+dst[i+2])* .5 ) 120 | ) 121 | } 122 | 123 | //extremely brutal way of doing this but hey... 124 | var group = new THREE.Group(); 125 | for( i = 0; i < 100; i++ ){ 126 | 127 | var vectors = []; 128 | origin = nodes.splice( parseInt( Math.random() * nodes.length ), 1 )[0]; 129 | vectors.push( origin ); 130 | for( var j = 0; j < 16; j++ ){ 131 | 132 | 133 | nodes.sort( function( a, b ){ 134 | return a.distanceToSquared( origin ) - b.distanceToSquared( origin ); 135 | }); 136 | 137 | var n = nodes.splice(~~(Math.random() * 10 ),1)[0]; 138 | vectors.push( n ); 139 | origin = n; 140 | } 141 | 142 | var material = new MeshLineMaterial( { 143 | useMap: false, 144 | color: new THREE.Color( colors[ parseInt( Math.random() * colors.length ) ] ),//0xFFFFFF ), 145 | opacity: 1, 146 | resolution: resolution, 147 | sizeAttenuation: true, 148 | lineWidth: 1 + ( ( Math.random() > .35 ? 1 : 0 )*~~(Math.random() * 3 ) ), 149 | near: camera.near, 150 | far: camera.far, 151 | depthWrite: false, 152 | transparent: true 153 | }, 154 | assetsLoader.meshline_vs, 155 | assetsLoader.meshline_fs); 156 | 157 | 158 | var spl = new THREE.CatmullRomCurve3( vectors ); 159 | var res = spl.getPoints( vectors.length * 5 ); 160 | var path = []; 161 | res.forEach(function( p, i, a ){ 162 | path.push( p.x, p.y, p.z ); 163 | }); 164 | 165 | var l = new MeshLine(); 166 | l.setGeometry( path, function( p ) { return 1; } ); 167 | 168 | var line = new THREE.Mesh( l.geometry, material ); 169 | line.startTime = Math.random() * 3 * 1000; 170 | line.lineLength = .25; 171 | line.speed = .0001; 172 | lines.push( line ); 173 | group.add( line ); 174 | 175 | } 176 | 177 | scene.add( group ); 178 | 179 | } 180 | 181 | function render() { 182 | 183 | requestAnimationFrame( render ); 184 | controls.update(); 185 | 186 | lines.forEach( function(l){ 187 | 188 | var t = ( ( Date.now() - l.startTime ) * l.speed ) % ( 1 + l.lineLength ); 189 | l.material.uniforms.visibility.value.x = t - l.lineLength; 190 | l.material.uniforms.visibility.value.y = t; 191 | 192 | }); 193 | renderer.render( scene, camera ); 194 | 195 | } 196 | -------------------------------------------------------------------------------- /js/dwarf_bk.js: -------------------------------------------------------------------------------- 1 | 2 | var dwarf, env, particles; 3 | window.onload = function(){ 4 | 5 | var queue = [ 6 | 7 | {name: "particles_vs", url: "./glsl/line_sem_vs.glsl", type:assetsLoader.TXT }, 8 | {name: "particles_fs", url: "./glsl/line_sem_fs.glsl", type:assetsLoader.TXT }, 9 | {name: "sem_vs", url: "./glsl/sem_vs.glsl", type:assetsLoader.TXT }, 10 | {name: "sem_fs", url: "./glsl/sem_fs.glsl", type:assetsLoader.TXT }, 11 | {name: "env_vs", url: "./glsl/env_vs.glsl", type:assetsLoader.TXT }, 12 | {name: "env_fs", url: "./glsl/env_fs.glsl", type:assetsLoader.TXT }, 13 | 14 | { 15 | name: "dwarfTexture", 16 | url: "./assets/textures/matcap/thuglee-03.jpg",type:assetsLoader.IMG 17 | }, 18 | { 19 | name: "dwarf", 20 | url: "./assets/models/binaries/dwarf.js",type:assetsLoader.MOD 21 | }, 22 | { 23 | name: "particles", 24 | url:"./assets/models/particles/dwarf/dwarf2k.txt", type:assetsLoader.TXT, 25 | onLoad:function (txt) { 26 | var obj = {}; 27 | var res = txt.split( '|' ); 28 | obj.pos = res[0].split(',').map( function( v ){return parseFloat( v ); } ); 29 | obj.dst = res[1].split(',').map( function( v ){return parseFloat( v ); } ); 30 | assetsLoader.particles = obj; 31 | } 32 | } 33 | 34 | ]; 35 | 36 | assetsLoader.load(queue, init); 37 | }; 38 | 39 | function init() { 40 | 41 | init3D(); 42 | 43 | camera.position.x = 100; 44 | camera.position.y = -45; 45 | camera.position.z = 350; 46 | 47 | createMaterials(); 48 | createMeshes(); 49 | createParticles(); 50 | 51 | scene.add(env); 52 | scene.add( particles ); 53 | scene.add(dwarf); 54 | 55 | render(); 56 | } 57 | 58 | function createMaterials(){ 59 | 60 | startTime = Date.now(); 61 | 62 | materials.dwarf = new THREE.ShaderMaterial({ 63 | uniforms:{ 64 | tMatCap : {type:"t", value:assetsLoader.dwarfTexture }, 65 | time:{type:"f", value:0 }, 66 | alpha:{type:"f", value:.35 } 67 | }, 68 | vertexShader:assetsLoader.sem_vs, 69 | fragmentShader:assetsLoader.sem_fs, 70 | blending:THREE.MultiplyBlending, 71 | transparent: true, 72 | side:THREE.FrontSide, 73 | depthWrite:false 74 | }); 75 | 76 | materials.particles = new THREE.LineBasicMaterial({ 77 | color:0x000000, 78 | transparent:true, 79 | opacity: .25 80 | }); 81 | 82 | materials.environment = new THREE.ShaderMaterial({ 83 | uniforms : { 84 | horizon:{type:"f", value: .45 }, 85 | spread:{type:"f", value: .05 }, 86 | topColor:{type:"v3", value:new THREE.Color( 0xEEEEEE )}, 87 | bottomColor:{type:"v3", value:new THREE.Color( 0xBBBBBB )} 88 | }, 89 | vertexShader: assetsLoader.env_vs, 90 | fragmentShader: assetsLoader.env_fs, 91 | side:THREE.BackSide 92 | }); 93 | 94 | } 95 | 96 | function createMeshes() { 97 | 98 | assetsLoader.dwarf.computeVertexNormals(); 99 | dwarf = new THREE.Mesh(assetsLoader.dwarf, materials.dwarf ); 100 | 101 | env = new THREE.Mesh(new THREE.CylinderBufferGeometry(.5, .5, 1, 64), materials.environment); 102 | env.scale.multiplyScalar(1000); 103 | 104 | } 105 | 106 | 107 | function createParticles(){ 108 | 109 | if( assetsLoader.particles === undefined ){ 110 | 111 | var model = dwarf; 112 | var count = Math.pow( 2, 11 );//->2048 113 | 114 | assetsLoader.particles = Scatter.distribute( model, count ); 115 | Scatter.toString( assetsLoader.particles, 3, "dwarf"+~~(count/1000)+"k" ); 116 | 117 | } 118 | 119 | var pos = assetsLoader.particles.pos; 120 | var dst = assetsLoader.particles.dst; 121 | var buffer = new Float32Array( pos.length * 2 ); 122 | for( var i = 0; i< pos.length; i+=3 ){ 123 | 124 | var id = i * 2; 125 | buffer[ id++ ] = pos[ i ]; 126 | buffer[ id++ ] = pos[ i + 1 ]; 127 | buffer[ id++ ] = pos[ i + 2 ]; 128 | 129 | buffer[ id++ ] = dst[ i ]; 130 | buffer[ id++ ] = dst[ i + 1 ]; 131 | buffer[ id++ ] = dst[ i + 2 ]; 132 | 133 | } 134 | 135 | var g = new THREE.BufferGeometry(); 136 | g.addAttribute( "position", new THREE.BufferAttribute( buffer, 3 )); 137 | g.computeVertexNormals(); 138 | 139 | particles = new THREE.LineSegments(g,materials.particles ); 140 | 141 | } 142 | 143 | 144 | function render() { 145 | 146 | requestAnimationFrame( render ); 147 | controls.update(); 148 | 149 | var time = ( Date.now() - startTime ) * 0.001; 150 | for( var k in materials ){ 151 | 152 | if( materials[ k ].uniforms !== undefined && materials[ k ].uniforms.time !== undefined ){ 153 | 154 | materials[ k ].uniforms.time.value = time; 155 | 156 | } 157 | } 158 | 159 | renderer.render( scene, camera ); 160 | 161 | } 162 | -------------------------------------------------------------------------------- /js/plane.js: -------------------------------------------------------------------------------- 1 | 2 | var plane, env, particles; 3 | window.onload = function(){ 4 | 5 | var queue = [ 6 | 7 | {name: "particles_vs", url: "./glsl/line_sem_vs.glsl", type:assetsLoader.TXT }, 8 | {name: "particles_fs", url: "./glsl/line_sem_fs.glsl", type:assetsLoader.TXT }, 9 | {name: "sem_vs", url: "./glsl/sem_vs.glsl", type:assetsLoader.TXT }, 10 | {name: "sem_fs", url: "./glsl/sem_fs.glsl", type:assetsLoader.TXT }, 11 | {name: "env_vs", url: "./glsl/env_vs.glsl", type:assetsLoader.TXT }, 12 | {name: "env_fs", url: "./glsl/env_fs.glsl", type:assetsLoader.TXT }, 13 | 14 | { 15 | name: "planeTexture", 16 | // url: "./assets/textures/matcap/untitled.6.jpg",type:assetsLoader.IMG 17 | url: "./assets/textures/matcap/thuglee-03.jpg",type:assetsLoader.IMG 18 | }, 19 | { 20 | name: "plane", 21 | url: "./assets/models/binaries/plane.js",type:assetsLoader.MOD 22 | }, 23 | { 24 | name: "particles", 25 | url:"./assets/models/particles/plane/plane65k.txt", type:assetsLoader.TXT, 26 | onLoad:function (txt) { 27 | var obj = {}; 28 | var res = txt.split( '|' ); 29 | obj.pos = res[0].split(',').map( function( v ){return parseFloat( v ); } ); 30 | obj.dst = res[1].split(',').map( function( v ){return parseFloat( v ); } ); 31 | assetsLoader.particles = obj; 32 | } 33 | } 34 | ]; 35 | 36 | assetsLoader.load(queue, init); 37 | }; 38 | 39 | function init() { 40 | 41 | init3D(); 42 | 43 | camera.position.x = -200; 44 | camera.position.y = 250; 45 | camera.position.z = 180; 46 | 47 | controls.target.set( 16, 22, -13); 48 | 49 | createMaterials(); 50 | createMeshes(); 51 | createParticles(); 52 | 53 | scene.add(env); 54 | scene.add( plane ); 55 | scene.add( particles ); 56 | 57 | render(); 58 | } 59 | 60 | function createMaterials(){ 61 | 62 | startTime = Date.now(); 63 | 64 | materials.plane = new THREE.ShaderMaterial({ 65 | uniforms:{ 66 | tMatCap : {type:"t", value:assetsLoader.planeTexture }, 67 | time:{type:"f", value:0 }, 68 | alpha:{type:"f", value:.85 } 69 | }, 70 | vertexShader:assetsLoader.sem_vs, 71 | fragmentShader:assetsLoader.sem_fs, 72 | blending:THREE.MultiplyBlending, 73 | transparent: true, 74 | side:THREE.FrontSide, 75 | depthWrite:false 76 | }); 77 | 78 | materials.particles = new THREE.LineBasicMaterial({ 79 | color:0x000000, 80 | transparent:true, 81 | opacity: .2 82 | }); 83 | 84 | materials.environment = new THREE.ShaderMaterial({ 85 | uniforms : { 86 | horizon:{type:"f", value: .45 }, 87 | spread:{type:"f", value: .05 }, 88 | topColor:{type:"v3", value:new THREE.Color( 0xEEEEEE )}, 89 | bottomColor:{type:"v3", value:new THREE.Color( 0xBBBBBB )} 90 | }, 91 | vertexShader: assetsLoader.env_vs, 92 | fragmentShader: assetsLoader.env_fs, 93 | side:THREE.BackSide 94 | }); 95 | 96 | } 97 | 98 | function createMeshes() { 99 | 100 | assetsLoader.plane.computeVertexNormals(); 101 | plane = new THREE.Mesh(assetsLoader.plane, materials.plane ); 102 | 103 | env = new THREE.Mesh(new THREE.CylinderBufferGeometry(.5, .5, 1, 64), materials.environment); 104 | env.scale.multiplyScalar(1000); 105 | 106 | } 107 | 108 | 109 | function createParticles(){ 110 | 111 | if( assetsLoader.particles === undefined ){ 112 | 113 | var model = plane; 114 | var count = Math.pow( 2, 16 );//->65536 115 | 116 | assetsLoader.particles = Scatter.distribute( model, count ); 117 | Scatter.toString( assetsLoader.particles, 3, "plane"+~~(count/1000)+"k" ); 118 | 119 | } 120 | 121 | var pos = assetsLoader.particles.pos; 122 | var dst = assetsLoader.particles.dst; 123 | var buffer = new Float32Array( pos.length * 2 ); 124 | for( var i = 0; i< pos.length; i+=3 ){ 125 | 126 | var id = i * 2; 127 | buffer[ id++ ] = pos[ i ]; 128 | buffer[ id++ ] = pos[ i + 1 ]; 129 | buffer[ id++ ] = pos[ i + 2 ]; 130 | 131 | buffer[ id++ ] = dst[ i ]; 132 | buffer[ id++ ] = dst[ i + 1 ]; 133 | buffer[ id++ ] = dst[ i + 2 ]; 134 | 135 | } 136 | 137 | var g = new THREE.BufferGeometry(); 138 | g.addAttribute( "position", new THREE.BufferAttribute( buffer, 3 )); 139 | g.computeVertexNormals(); 140 | 141 | particles = new THREE.LineSegments(g,materials.particles ); 142 | 143 | } 144 | 145 | 146 | function render() { 147 | 148 | requestAnimationFrame( render ); 149 | controls.update(); 150 | 151 | var time = ( Date.now() - startTime ) * 0.001; 152 | for( var k in materials ){ 153 | 154 | if( materials[ k ].uniforms !== undefined && materials[ k ].uniforms.time !== undefined ){ 155 | 156 | materials[ k ].uniforms.time.value = time; 157 | 158 | } 159 | } 160 | 161 | renderer.render( scene, camera ); 162 | 163 | } 164 | -------------------------------------------------------------------------------- /js/spider.js: -------------------------------------------------------------------------------- 1 | 2 | var spider, env, particles; 3 | window.onload = function(){ 4 | 5 | var queue = [ 6 | 7 | {name: "particles_vs", url: "./glsl/particles_vs.glsl", type:assetsLoader.TXT }, 8 | {name: "particles_fs", url: "./glsl/particles_fs.glsl", type:assetsLoader.TXT }, 9 | {name: "sem_vs", url: "./glsl/sem_vs.glsl", type:assetsLoader.TXT }, 10 | {name: "sem_fs", url: "./glsl/sem_fs.glsl", type:assetsLoader.TXT }, 11 | {name: "env_vs", url: "./glsl/env_vs.glsl", type:assetsLoader.TXT }, 12 | {name: "env_fs", url: "./glsl/env_fs.glsl", type:assetsLoader.TXT }, 13 | 14 | { 15 | name: "spiderTexture", 16 | // url: "./assets/textures/matcap/chrome_eye.png",type:assetsLoader.IMG 17 | url: "./assets/textures/matcap/droplet_01.png",type:assetsLoader.IMG 18 | }, 19 | { 20 | name: "particlesTexture", 21 | url: "./assets/textures/particles.png",type:assetsLoader.IMG 22 | }, 23 | { 24 | name: "spider", 25 | url: "./assets/models/binaries/spider.js",type:assetsLoader.MOD 26 | }, 27 | 28 | { 29 | name: "particles", 30 | url:"./assets/models/particles/spider/spider32k.txt", type:assetsLoader.TXT, 31 | onLoad:function (txt) { 32 | var obj = {}; 33 | var res = txt.split( '|' ); 34 | obj.pos = res[0].split(',').map( function( v ){return parseFloat( v ); } ); 35 | obj.dst = res[1].split(',').map( function( v ){return parseFloat( v ); } ); 36 | assetsLoader.particles = obj; 37 | } 38 | } 39 | 40 | ]; 41 | 42 | assetsLoader.load(queue, init); 43 | }; 44 | 45 | function init() { 46 | 47 | init3D(); 48 | 49 | camera.position.x = -70; 50 | camera.position.y = 140; 51 | camera.position.z = 60; 52 | 53 | createMaterials(); 54 | createMeshes(); 55 | createParticles(); 56 | 57 | scene.add( particles ); 58 | scene.add(spider); 59 | scene.add(env); 60 | 61 | 62 | render(); 63 | 64 | } 65 | 66 | function createMaterials(){ 67 | 68 | startTime = Date.now(); 69 | 70 | materials.spiderTexture = new THREE.ShaderMaterial({ 71 | uniforms:{ 72 | tMatCap : {type:"t", value:assetsLoader.spiderTexture }, 73 | time:{type:"f", value:0 }, 74 | alpha:{type:"f", value:.75 } 75 | }, 76 | vertexShader:assetsLoader.sem_vs, 77 | fragmentShader:assetsLoader.sem_fs, 78 | blending:THREE.AdditiveBlending, 79 | // side:THREE.DoubleSide, 80 | depthWrite:false, 81 | transparent: true 82 | }); 83 | 84 | materials.particles = new THREE.ShaderMaterial({ 85 | uniforms : { 86 | color0:{type:"v3", value:new THREE.Color( 0x00CCFF )}, 87 | color1:{type:"v3", value:new THREE.Color( 0xFFCC00 )}, 88 | bounds:{type:"v2", value:new THREE.Vector2( .25, .5 )},//start / length 89 | time:{type:"f", value:0}, 90 | modBig:{type:"f", value:100}, 91 | pointSize:{type:"f", value:2}, 92 | alpha:{type:"f", value:1} 93 | }, 94 | vertexShader: assetsLoader.particles_vs, 95 | fragmentShader: assetsLoader.particles_fs, 96 | transparent: true 97 | }); 98 | 99 | materials.environment = new THREE.ShaderMaterial({ 100 | uniforms : { 101 | horizon:{type:"f", value: .45 }, 102 | spread:{type:"f", value: .05 }, 103 | topColor:{type:"v3", value:new THREE.Color( 0x303030 )}, 104 | bottomColor:{type:"v3", value:new THREE.Color( 0x101010 )} 105 | }, 106 | vertexShader: assetsLoader.env_vs, 107 | fragmentShader: assetsLoader.env_fs, 108 | side:THREE.BackSide, 109 | depthWrite:false 110 | }); 111 | 112 | } 113 | 114 | function createMeshes() { 115 | 116 | assetsLoader.spider.computeVertexNormals(); 117 | spider = new THREE.Mesh(assetsLoader.spider, materials.spiderTexture ); 118 | 119 | env = new THREE.Mesh(new THREE.CylinderBufferGeometry(.5, .5, 1, 64), materials.environment); 120 | env.scale.multiplyScalar(1000); 121 | 122 | } 123 | 124 | 125 | function createParticles(){ 126 | 127 | if( assetsLoader.particles === undefined ){ 128 | 129 | var model = spider; 130 | var count = Math.pow( 2, 15 ); 131 | 132 | assetsLoader.particles = Scatter.distribute( model, count ); 133 | Scatter.toString( assetsLoader.particles, 3, "spider32k" ); 134 | 135 | } 136 | 137 | var g = new THREE.BufferGeometry(); 138 | g.addAttribute( "position", new THREE.BufferAttribute( new Float32Array( assetsLoader.particles.pos ), 3 )); 139 | g.addAttribute( "dest", new THREE.BufferAttribute( new Float32Array( assetsLoader.particles.dst ), 3 )); 140 | particles = new THREE.Points(g,materials.particles); 141 | } 142 | 143 | 144 | function render() { 145 | 146 | requestAnimationFrame( render ); 147 | controls.update(); 148 | 149 | var time = ( Date.now() - startTime ) * 0.001; 150 | for( var k in materials ){ 151 | 152 | if( materials[ k ].uniforms.time !== undefined ){ 153 | 154 | materials[ k ].uniforms.time.value = time; 155 | 156 | } 157 | } 158 | 159 | renderer.render( scene, camera ); 160 | 161 | } 162 | -------------------------------------------------------------------------------- /js/suzanne.js: -------------------------------------------------------------------------------- 1 | 2 | var skeleton, invertSkeleton, env, particles; 3 | 4 | window.onload = function(){ 5 | 6 | var queue = [ 7 | 8 | {name: "particles_vs", url: "./glsl/texture_particles_vs.glsl", type:assetsLoader.TXT }, 9 | {name: "particles_fs", url: "./glsl/texture_particles_fs.glsl", type:assetsLoader.TXT }, 10 | {name: "sem_vs", url: "./glsl/sem_vs.glsl", type:assetsLoader.TXT }, 11 | {name: "sem_fs", url: "./glsl/sem_fs.glsl", type:assetsLoader.TXT }, 12 | {name: "env_vs", url: "./glsl/env_vs.glsl", type:assetsLoader.TXT }, 13 | {name: "env_fs", url: "./glsl/env_fs.glsl", type:assetsLoader.TXT }, 14 | 15 | { 16 | name: "silver", 17 | url: "./assets/textures/matcap/test_steel.jpg",type:assetsLoader.IMG 18 | }, 19 | { 20 | name: "blue", 21 | url: "./assets/textures/matcap/JG_Drink01.png",type:assetsLoader.IMG 22 | }, 23 | { 24 | name: "particlesTexture", 25 | url: "./assets/textures/particles.png",type:assetsLoader.IMG 26 | }, 27 | 28 | { 29 | name: "skeleton", 30 | url: "./assets/models/binaries/suzanne.js",type:assetsLoader.MOD 31 | }, 32 | { 33 | name: "invert", 34 | url: "./assets/models/binaries/suzanne_invert.js",type:assetsLoader.MOD 35 | }, 36 | { 37 | name: "particles", 38 | url:"./assets/models/particles/suzanne/volume65k.txt", type:assetsLoader.TXT, 39 | onLoad:function (txt) { 40 | var obj = {}; 41 | var res = txt.split( '|' ); 42 | obj.pos = res[0].split(',').map( function( v ){return parseFloat( v ); } ); 43 | obj.dst = res[1].split(',').map( function( v ){return parseFloat( v ); } ); 44 | assetsLoader.particles = obj; 45 | } 46 | } 47 | 48 | ]; 49 | assetsLoader.load(queue, init); 50 | }; 51 | 52 | function init() { 53 | 54 | init3D(); 55 | camera.position.x = 0; 56 | camera.position.y = 7; 57 | camera.position.z = 20; 58 | 59 | createMaterials(); 60 | 61 | createMeshes(); 62 | createParticles(); 63 | 64 | scene.add(skeleton); 65 | scene.add(invertSkeleton); 66 | scene.add(env); 67 | scene.add( particles ); 68 | 69 | 70 | render(); 71 | 72 | } 73 | 74 | function createMaterials(){ 75 | 76 | startTime = Date.now(); 77 | 78 | materials.silver = new THREE.ShaderMaterial({ 79 | uniforms:{ 80 | tMatCap : {type:"t", value:assetsLoader.silver }, 81 | time:{type:"f", value:0 }, 82 | alpha:{type:"f", value:0 } 83 | }, 84 | vertexShader:assetsLoader.sem_vs, 85 | fragmentShader:assetsLoader.sem_fs 86 | }); 87 | 88 | materials.blue = new THREE.ShaderMaterial({ 89 | uniforms:{ 90 | tMatCap : {type:"t", value:assetsLoader.blue }, 91 | time:{type:"f", value:0 }, 92 | alpha:{type:"f", value:0.45 } 93 | }, 94 | vertexShader:assetsLoader.sem_vs, 95 | fragmentShader:assetsLoader.sem_fs, 96 | transparent: true, 97 | side:THREE.DoubleSide, 98 | depthWrite:false 99 | }); 100 | 101 | materials.particles = new THREE.ShaderMaterial({ 102 | uniforms : { 103 | texture:{type:"t", value:assetsLoader.particlesTexture}, 104 | time:{type:"f", value:0}, 105 | modBig:{type:"f", value:25}, 106 | pointSize:{type:"f", value:4}, 107 | alpha:{type:"f", value:1} 108 | }, 109 | vertexShader: assetsLoader.particles_vs, 110 | fragmentShader: assetsLoader.particles_fs, 111 | transparent: true 112 | }); 113 | 114 | materials.environment = new THREE.ShaderMaterial({ 115 | uniforms : { 116 | horizon:{type:"f", value: .45 }, 117 | spread:{type:"f", value: .05 }, 118 | topColor:{type:"v3", value:new THREE.Color( 0x505050 )}, 119 | bottomColor:{type:"v3", value:new THREE.Color( 0x101010 )} 120 | }, 121 | vertexShader: assetsLoader.env_vs, 122 | fragmentShader: assetsLoader.env_fs, 123 | side:THREE.BackSide, 124 | depthWrite:false 125 | }); 126 | 127 | } 128 | 129 | function createMeshes() { 130 | 131 | skeleton = new THREE.Mesh(assetsLoader.skeleton, materials.silver); 132 | 133 | invertSkeleton = new THREE.Mesh(assetsLoader.invert, materials.blue); 134 | 135 | env = new THREE.Mesh(new THREE.CylinderBufferGeometry(.5, .5, 1, 64), materials.environment); 136 | env.scale.multiplyScalar(1000); 137 | 138 | } 139 | 140 | 141 | function createParticles(){ 142 | 143 | if( assetsLoader.particles === undefined ){ 144 | 145 | var model = invertSkeleton; 146 | var count = Math.pow( 2, 16 ); 147 | 148 | assetsLoader.particles = Scatter.distribute( model, count ); 149 | Scatter.toString( assetsLoader.particles, 3, "surface65k" ); 150 | 151 | } 152 | 153 | var g = new THREE.BufferGeometry(); 154 | g.addAttribute( "position", new THREE.BufferAttribute( new Float32Array( assetsLoader.particles.pos ), 3 )); 155 | g.addAttribute( "dest", new THREE.BufferAttribute( new Float32Array( assetsLoader.particles.dst ), 3 )); 156 | 157 | //adds uvs to the particles (the texture is a 4*4 spritesheet 158 | var uvCount = ( g.getAttribute("position").array.length / 3 ) * 2; 159 | var uvOffset = new Float32Array( uvCount ); 160 | var i = 0; 161 | while( i < uvCount ){ 162 | uvOffset[ i++ ] = Math.floor( Math.random() * 4 ) / 4; 163 | } 164 | g.addAttribute( "uvOffset", new THREE.BufferAttribute( uvOffset, 2 )); 165 | particles = new THREE.Points(g,materials.particles); 166 | 167 | } 168 | 169 | 170 | function render() { 171 | 172 | requestAnimationFrame( render ); 173 | controls.update(); 174 | 175 | var time = ( Date.now() - startTime ) * 0.001; 176 | for( var k in materials ){ 177 | 178 | if( materials[ k ].uniforms.time !== undefined ){ 179 | 180 | materials[ k ].uniforms.time.value = time; 181 | 182 | } 183 | } 184 | 185 | renderer.render( scene, camera ); 186 | 187 | } 188 | -------------------------------------------------------------------------------- /plane.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | THREE.MeshLine - Shape example 6 | 7 | 8 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /spider.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | THREE.MeshLine - Shape example 6 | 7 | 8 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /sreenshots/4k.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/sreenshots/4k.png -------------------------------------------------------------------------------- /sreenshots/4k0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/sreenshots/4k0.png -------------------------------------------------------------------------------- /sreenshots/4k1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/sreenshots/4k1.png -------------------------------------------------------------------------------- /sreenshots/4k2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/sreenshots/4k2.png -------------------------------------------------------------------------------- /sreenshots/4k3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/sreenshots/4k3.png -------------------------------------------------------------------------------- /sreenshots/8k0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/sreenshots/8k0.png -------------------------------------------------------------------------------- /sreenshots/8k1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/sreenshots/8k1.png -------------------------------------------------------------------------------- /sreenshots/lines0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/sreenshots/lines0.png -------------------------------------------------------------------------------- /sreenshots/lines1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/sreenshots/lines1.png -------------------------------------------------------------------------------- /sreenshots/spider0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicoptere/volume_distribution/2554d9d96a278a3cd24b2b3b39bb5554c89b98fc/sreenshots/spider0.png -------------------------------------------------------------------------------- /suzanne.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | THREE.MeshLine - Shape example 6 | 7 | 8 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /vendor/BinaryLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.BinaryLoader = function ( manager ) { 6 | 7 | if ( typeof manager === 'boolean' ) { 8 | 9 | console.warn( 'THREE.BinaryLoader: showStatus parameter has been removed from constructor.' ); 10 | manager = undefined; 11 | 12 | } 13 | 14 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 15 | 16 | }; 17 | 18 | THREE.BinaryLoader.prototype = { 19 | 20 | constructor: THREE.BinaryLoader, 21 | 22 | // Load models generated by slim OBJ converter with BINARY option (converter_obj_three_slim.py -t binary) 23 | // - binary models consist of two files: JS and BIN 24 | // - parameters 25 | // - url (required) 26 | // - callback (required) 27 | // - texturePath (optional: if not specified, textures will be assumed to be in the same folder as JS model file) 28 | // - binaryPath (optional: if not specified, binary file will be assumed to be in the same folder as JS model file) 29 | load: function ( url, onLoad, onProgress, onError ) { 30 | 31 | // todo: unify load API to for easier SceneLoader use 32 | 33 | var texturePath = this.texturePath || THREE.Loader.prototype.extractUrlBase( url ); 34 | var binaryPath = this.binaryPath || THREE.Loader.prototype.extractUrlBase( url ); 35 | 36 | // #1 load JS part via web worker 37 | 38 | var scope = this; 39 | 40 | var jsonloader = new THREE.FileLoader( this.manager ); 41 | jsonloader.load( url, function ( data ) { 42 | 43 | var json = JSON.parse( data ); 44 | 45 | var bufferUrl = binaryPath + json.buffers; 46 | 47 | var bufferLoader = new THREE.FileLoader( scope.manager ); 48 | bufferLoader.setResponseType( 'arraybuffer' ); 49 | bufferLoader.load( bufferUrl, function ( bufData ) { 50 | 51 | // IEWEBGL needs this ??? 52 | //buffer = ( new Uint8Array( xhr.responseBody ) ).buffer; 53 | 54 | //// iOS and other XMLHttpRequest level 1 ??? 55 | 56 | scope.parse( bufData, onLoad, texturePath, json.materials ); 57 | 58 | }, onProgress, onError ); 59 | 60 | }, onProgress, onError ); 61 | 62 | }, 63 | 64 | setBinaryPath: function ( value ) { 65 | 66 | this.binaryPath = value; 67 | 68 | }, 69 | 70 | setCrossOrigin: function ( value ) { 71 | 72 | this.crossOrigin = value; 73 | 74 | }, 75 | 76 | setTexturePath: function ( value ) { 77 | 78 | this.texturePath = value; 79 | 80 | }, 81 | 82 | parse: function ( data, callback, texturePath, jsonMaterials ) { 83 | 84 | var Model = function ( texturePath ) { 85 | 86 | var scope = this, 87 | currentOffset = 0, 88 | md, 89 | normals = [], 90 | uvs = [], 91 | start_tri_flat, start_tri_smooth, start_tri_flat_uv, start_tri_smooth_uv, 92 | start_quad_flat, start_quad_smooth, start_quad_flat_uv, start_quad_smooth_uv, 93 | tri_size, quad_size, 94 | len_tri_flat, len_tri_smooth, len_tri_flat_uv, len_tri_smooth_uv, 95 | len_quad_flat, len_quad_smooth, len_quad_flat_uv, len_quad_smooth_uv; 96 | 97 | 98 | THREE.Geometry.call( this ); 99 | 100 | md = parseMetaData( data, currentOffset ); 101 | 102 | currentOffset += md.header_bytes; 103 | /* 104 | md.vertex_index_bytes = Uint32Array.BYTES_PER_ELEMENT; 105 | md.material_index_bytes = Uint16Array.BYTES_PER_ELEMENT; 106 | md.normal_index_bytes = Uint32Array.BYTES_PER_ELEMENT; 107 | md.uv_index_bytes = Uint32Array.BYTES_PER_ELEMENT; 108 | */ 109 | // buffers sizes 110 | 111 | tri_size = md.vertex_index_bytes * 3 + md.material_index_bytes; 112 | quad_size = md.vertex_index_bytes * 4 + md.material_index_bytes; 113 | 114 | len_tri_flat = md.ntri_flat * ( tri_size ); 115 | len_tri_smooth = md.ntri_smooth * ( tri_size + md.normal_index_bytes * 3 ); 116 | len_tri_flat_uv = md.ntri_flat_uv * ( tri_size + md.uv_index_bytes * 3 ); 117 | len_tri_smooth_uv = md.ntri_smooth_uv * ( tri_size + md.normal_index_bytes * 3 + md.uv_index_bytes * 3 ); 118 | 119 | len_quad_flat = md.nquad_flat * ( quad_size ); 120 | len_quad_smooth = md.nquad_smooth * ( quad_size + md.normal_index_bytes * 4 ); 121 | len_quad_flat_uv = md.nquad_flat_uv * ( quad_size + md.uv_index_bytes * 4 ); 122 | len_quad_smooth_uv = md.nquad_smooth_uv * ( quad_size + md.normal_index_bytes * 4 + md.uv_index_bytes * 4 ); 123 | 124 | // read buffers 125 | 126 | currentOffset += init_vertices( currentOffset ); 127 | 128 | currentOffset += init_normals( currentOffset ); 129 | currentOffset += handlePadding( md.nnormals * 3 ); 130 | 131 | currentOffset += init_uvs( currentOffset ); 132 | 133 | start_tri_flat = currentOffset; 134 | start_tri_smooth = start_tri_flat + len_tri_flat + handlePadding( md.ntri_flat * 2 ); 135 | start_tri_flat_uv = start_tri_smooth + len_tri_smooth + handlePadding( md.ntri_smooth * 2 ); 136 | start_tri_smooth_uv = start_tri_flat_uv + len_tri_flat_uv + handlePadding( md.ntri_flat_uv * 2 ); 137 | 138 | start_quad_flat = start_tri_smooth_uv + len_tri_smooth_uv + handlePadding( md.ntri_smooth_uv * 2 ); 139 | start_quad_smooth = start_quad_flat + len_quad_flat + handlePadding( md.nquad_flat * 2 ); 140 | start_quad_flat_uv = start_quad_smooth + len_quad_smooth + handlePadding( md.nquad_smooth * 2 ); 141 | start_quad_smooth_uv = start_quad_flat_uv + len_quad_flat_uv + handlePadding( md.nquad_flat_uv * 2 ); 142 | 143 | // have to first process faces with uvs 144 | // so that face and uv indices match 145 | 146 | init_triangles_flat_uv( start_tri_flat_uv ); 147 | init_triangles_smooth_uv( start_tri_smooth_uv ); 148 | 149 | init_quads_flat_uv( start_quad_flat_uv ); 150 | init_quads_smooth_uv( start_quad_smooth_uv ); 151 | 152 | // now we can process untextured faces 153 | 154 | init_triangles_flat( start_tri_flat ); 155 | init_triangles_smooth( start_tri_smooth ); 156 | 157 | init_quads_flat( start_quad_flat ); 158 | init_quads_smooth( start_quad_smooth ); 159 | 160 | this.computeFaceNormals(); 161 | 162 | function handlePadding( n ) { 163 | 164 | return ( n % 4 ) ? ( 4 - n % 4 ) : 0; 165 | 166 | } 167 | 168 | function parseMetaData( data, offset ) { 169 | 170 | var metaData = { 171 | 172 | 'signature' : parseString( data, offset, 12 ), 173 | 'header_bytes' : parseUChar8( data, offset + 12 ), 174 | 175 | 'vertex_coordinate_bytes' : parseUChar8( data, offset + 13 ), 176 | 'normal_coordinate_bytes' : parseUChar8( data, offset + 14 ), 177 | 'uv_coordinate_bytes' : parseUChar8( data, offset + 15 ), 178 | 179 | 'vertex_index_bytes' : parseUChar8( data, offset + 16 ), 180 | 'normal_index_bytes' : parseUChar8( data, offset + 17 ), 181 | 'uv_index_bytes' : parseUChar8( data, offset + 18 ), 182 | 'material_index_bytes' : parseUChar8( data, offset + 19 ), 183 | 184 | 'nvertices' : parseUInt32( data, offset + 20 ), 185 | 'nnormals' : parseUInt32( data, offset + 20 + 4 * 1 ), 186 | 'nuvs' : parseUInt32( data, offset + 20 + 4 * 2 ), 187 | 188 | 'ntri_flat' : parseUInt32( data, offset + 20 + 4 * 3 ), 189 | 'ntri_smooth' : parseUInt32( data, offset + 20 + 4 * 4 ), 190 | 'ntri_flat_uv' : parseUInt32( data, offset + 20 + 4 * 5 ), 191 | 'ntri_smooth_uv' : parseUInt32( data, offset + 20 + 4 * 6 ), 192 | 193 | 'nquad_flat' : parseUInt32( data, offset + 20 + 4 * 7 ), 194 | 'nquad_smooth' : parseUInt32( data, offset + 20 + 4 * 8 ), 195 | 'nquad_flat_uv' : parseUInt32( data, offset + 20 + 4 * 9 ), 196 | 'nquad_smooth_uv' : parseUInt32( data, offset + 20 + 4 * 10 ) 197 | 198 | }; 199 | /* 200 | console.log( "signature: " + metaData.signature ); 201 | 202 | console.log( "header_bytes: " + metaData.header_bytes ); 203 | console.log( "vertex_coordinate_bytes: " + metaData.vertex_coordinate_bytes ); 204 | console.log( "normal_coordinate_bytes: " + metaData.normal_coordinate_bytes ); 205 | console.log( "uv_coordinate_bytes: " + metaData.uv_coordinate_bytes ); 206 | 207 | console.log( "vertex_index_bytes: " + metaData.vertex_index_bytes ); 208 | console.log( "normal_index_bytes: " + metaData.normal_index_bytes ); 209 | console.log( "uv_index_bytes: " + metaData.uv_index_bytes ); 210 | console.log( "material_index_bytes: " + metaData.material_index_bytes ); 211 | 212 | console.log( "nvertices: " + metaData.nvertices ); 213 | console.log( "nnormals: " + metaData.nnormals ); 214 | console.log( "nuvs: " + metaData.nuvs ); 215 | 216 | console.log( "ntri_flat: " + metaData.ntri_flat ); 217 | console.log( "ntri_smooth: " + metaData.ntri_smooth ); 218 | console.log( "ntri_flat_uv: " + metaData.ntri_flat_uv ); 219 | console.log( "ntri_smooth_uv: " + metaData.ntri_smooth_uv ); 220 | 221 | console.log( "nquad_flat: " + metaData.nquad_flat ); 222 | console.log( "nquad_smooth: " + metaData.nquad_smooth ); 223 | console.log( "nquad_flat_uv: " + metaData.nquad_flat_uv ); 224 | console.log( "nquad_smooth_uv: " + metaData.nquad_smooth_uv ); 225 | 226 | var total = metaData.header_bytes 227 | + metaData.nvertices * metaData.vertex_coordinate_bytes * 3 228 | + metaData.nnormals * metaData.normal_coordinate_bytes * 3 229 | + metaData.nuvs * metaData.uv_coordinate_bytes * 2 230 | + metaData.ntri_flat * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes ) 231 | + metaData.ntri_smooth * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 ) 232 | + metaData.ntri_flat_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.uv_index_bytes*3 ) 233 | + metaData.ntri_smooth_uv * ( metaData.vertex_index_bytes*3 + metaData.material_index_bytes + metaData.normal_index_bytes*3 + metaData.uv_index_bytes*3 ) 234 | + metaData.nquad_flat * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes ) 235 | + metaData.nquad_smooth * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 ) 236 | + metaData.nquad_flat_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.uv_index_bytes*4 ) 237 | + metaData.nquad_smooth_uv * ( metaData.vertex_index_bytes*4 + metaData.material_index_bytes + metaData.normal_index_bytes*4 + metaData.uv_index_bytes*4 ); 238 | console.log( "total bytes: " + total ); 239 | */ 240 | 241 | return metaData; 242 | 243 | } 244 | 245 | function parseString( data, offset, length ) { 246 | 247 | var charArray = new Uint8Array( data, offset, length ); 248 | 249 | var text = ""; 250 | 251 | for ( var i = 0; i < length; i ++ ) { 252 | 253 | text += String.fromCharCode( charArray[ offset + i ] ); 254 | 255 | } 256 | 257 | return text; 258 | 259 | } 260 | 261 | function parseUChar8( data, offset ) { 262 | 263 | var charArray = new Uint8Array( data, offset, 1 ); 264 | 265 | return charArray[ 0 ]; 266 | 267 | } 268 | 269 | function parseUInt32( data, offset ) { 270 | 271 | var intArray = new Uint32Array( data, offset, 1 ); 272 | 273 | return intArray[ 0 ]; 274 | 275 | } 276 | 277 | function init_vertices( start ) { 278 | 279 | var nElements = md.nvertices; 280 | 281 | var coordArray = new Float32Array( data, start, nElements * 3 ); 282 | 283 | var i, x, y, z; 284 | 285 | for ( i = 0; i < nElements; i ++ ) { 286 | 287 | x = coordArray[ i * 3 ]; 288 | y = coordArray[ i * 3 + 1 ]; 289 | z = coordArray[ i * 3 + 2 ]; 290 | 291 | scope.vertices.push( new THREE.Vector3( x, y, z ) ); 292 | 293 | } 294 | 295 | return nElements * 3 * Float32Array.BYTES_PER_ELEMENT; 296 | 297 | } 298 | 299 | function init_normals( start ) { 300 | 301 | var nElements = md.nnormals; 302 | 303 | if ( nElements ) { 304 | 305 | var normalArray = new Int8Array( data, start, nElements * 3 ); 306 | 307 | var i, x, y, z; 308 | 309 | for ( i = 0; i < nElements; i ++ ) { 310 | 311 | x = normalArray[ i * 3 ]; 312 | y = normalArray[ i * 3 + 1 ]; 313 | z = normalArray[ i * 3 + 2 ]; 314 | 315 | normals.push( x / 127, y / 127, z / 127 ); 316 | 317 | } 318 | 319 | } 320 | 321 | return nElements * 3 * Int8Array.BYTES_PER_ELEMENT; 322 | 323 | } 324 | 325 | function init_uvs( start ) { 326 | 327 | var nElements = md.nuvs; 328 | 329 | if ( nElements ) { 330 | 331 | var uvArray = new Float32Array( data, start, nElements * 2 ); 332 | 333 | var i, u, v; 334 | 335 | for ( i = 0; i < nElements; i ++ ) { 336 | 337 | u = uvArray[ i * 2 ]; 338 | v = uvArray[ i * 2 + 1 ]; 339 | 340 | uvs.push( u, v ); 341 | 342 | } 343 | 344 | } 345 | 346 | return nElements * 2 * Float32Array.BYTES_PER_ELEMENT; 347 | 348 | } 349 | 350 | function init_uvs3( nElements, offset ) { 351 | 352 | var i, uva, uvb, uvc, u1, u2, u3, v1, v2, v3; 353 | 354 | var uvIndexBuffer = new Uint32Array( data, offset, 3 * nElements ); 355 | 356 | for ( i = 0; i < nElements; i ++ ) { 357 | 358 | uva = uvIndexBuffer[ i * 3 ]; 359 | uvb = uvIndexBuffer[ i * 3 + 1 ]; 360 | uvc = uvIndexBuffer[ i * 3 + 2 ]; 361 | 362 | u1 = uvs[ uva * 2 ]; 363 | v1 = uvs[ uva * 2 + 1 ]; 364 | 365 | u2 = uvs[ uvb * 2 ]; 366 | v2 = uvs[ uvb * 2 + 1 ]; 367 | 368 | u3 = uvs[ uvc * 2 ]; 369 | v3 = uvs[ uvc * 2 + 1 ]; 370 | 371 | scope.faceVertexUvs[ 0 ].push( [ 372 | new THREE.Vector2( u1, v1 ), 373 | new THREE.Vector2( u2, v2 ), 374 | new THREE.Vector2( u3, v3 ) 375 | ] ); 376 | 377 | } 378 | 379 | } 380 | 381 | function init_uvs4( nElements, offset ) { 382 | 383 | var i, uva, uvb, uvc, uvd, u1, u2, u3, u4, v1, v2, v3, v4; 384 | 385 | var uvIndexBuffer = new Uint32Array( data, offset, 4 * nElements ); 386 | 387 | for ( i = 0; i < nElements; i ++ ) { 388 | 389 | uva = uvIndexBuffer[ i * 4 ]; 390 | uvb = uvIndexBuffer[ i * 4 + 1 ]; 391 | uvc = uvIndexBuffer[ i * 4 + 2 ]; 392 | uvd = uvIndexBuffer[ i * 4 + 3 ]; 393 | 394 | u1 = uvs[ uva * 2 ]; 395 | v1 = uvs[ uva * 2 + 1 ]; 396 | 397 | u2 = uvs[ uvb * 2 ]; 398 | v2 = uvs[ uvb * 2 + 1 ]; 399 | 400 | u3 = uvs[ uvc * 2 ]; 401 | v3 = uvs[ uvc * 2 + 1 ]; 402 | 403 | u4 = uvs[ uvd * 2 ]; 404 | v4 = uvs[ uvd * 2 + 1 ]; 405 | 406 | scope.faceVertexUvs[ 0 ].push( [ 407 | new THREE.Vector2( u1, v1 ), 408 | new THREE.Vector2( u2, v2 ), 409 | new THREE.Vector2( u4, v4 ) 410 | ] ); 411 | 412 | scope.faceVertexUvs[ 0 ].push( [ 413 | new THREE.Vector2( u2, v2 ), 414 | new THREE.Vector2( u3, v3 ), 415 | new THREE.Vector2( u4, v4 ) 416 | ] ); 417 | 418 | } 419 | 420 | } 421 | 422 | function init_faces3_flat( nElements, offsetVertices, offsetMaterials ) { 423 | 424 | var i, a, b, c, m; 425 | 426 | var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 3 * nElements ); 427 | var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); 428 | 429 | for ( i = 0; i < nElements; i ++ ) { 430 | 431 | a = vertexIndexBuffer[ i * 3 ]; 432 | b = vertexIndexBuffer[ i * 3 + 1 ]; 433 | c = vertexIndexBuffer[ i * 3 + 2 ]; 434 | 435 | m = materialIndexBuffer[ i ]; 436 | 437 | scope.faces.push( new THREE.Face3( a, b, c, null, null, m ) ); 438 | 439 | } 440 | 441 | } 442 | 443 | function init_faces4_flat( nElements, offsetVertices, offsetMaterials ) { 444 | 445 | var i, a, b, c, d, m; 446 | 447 | var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 4 * nElements ); 448 | var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); 449 | 450 | for ( i = 0; i < nElements; i ++ ) { 451 | 452 | a = vertexIndexBuffer[ i * 4 ]; 453 | b = vertexIndexBuffer[ i * 4 + 1 ]; 454 | c = vertexIndexBuffer[ i * 4 + 2 ]; 455 | d = vertexIndexBuffer[ i * 4 + 3 ]; 456 | 457 | m = materialIndexBuffer[ i ]; 458 | 459 | scope.faces.push( new THREE.Face3( a, b, d, null, null, m ) ); 460 | scope.faces.push( new THREE.Face3( b, c, d, null, null, m ) ); 461 | 462 | } 463 | 464 | } 465 | 466 | function init_faces3_smooth( nElements, offsetVertices, offsetNormals, offsetMaterials ) { 467 | 468 | var i, a, b, c, m; 469 | var na, nb, nc; 470 | 471 | var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 3 * nElements ); 472 | var normalIndexBuffer = new Uint32Array( data, offsetNormals, 3 * nElements ); 473 | var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); 474 | 475 | for ( i = 0; i < nElements; i ++ ) { 476 | 477 | a = vertexIndexBuffer[ i * 3 ]; 478 | b = vertexIndexBuffer[ i * 3 + 1 ]; 479 | c = vertexIndexBuffer[ i * 3 + 2 ]; 480 | 481 | na = normalIndexBuffer[ i * 3 ]; 482 | nb = normalIndexBuffer[ i * 3 + 1 ]; 483 | nc = normalIndexBuffer[ i * 3 + 2 ]; 484 | 485 | m = materialIndexBuffer[ i ]; 486 | 487 | var nax = normals[ na * 3 ], 488 | nay = normals[ na * 3 + 1 ], 489 | naz = normals[ na * 3 + 2 ], 490 | 491 | nbx = normals[ nb * 3 ], 492 | nby = normals[ nb * 3 + 1 ], 493 | nbz = normals[ nb * 3 + 2 ], 494 | 495 | ncx = normals[ nc * 3 ], 496 | ncy = normals[ nc * 3 + 1 ], 497 | ncz = normals[ nc * 3 + 2 ]; 498 | 499 | scope.faces.push( new THREE.Face3( a, b, c, [ 500 | new THREE.Vector3( nax, nay, naz ), 501 | new THREE.Vector3( nbx, nby, nbz ), 502 | new THREE.Vector3( ncx, ncy, ncz ) 503 | ], null, m ) ); 504 | 505 | } 506 | 507 | } 508 | 509 | function init_faces4_smooth( nElements, offsetVertices, offsetNormals, offsetMaterials ) { 510 | 511 | var i, a, b, c, d, m; 512 | var na, nb, nc, nd; 513 | 514 | var vertexIndexBuffer = new Uint32Array( data, offsetVertices, 4 * nElements ); 515 | var normalIndexBuffer = new Uint32Array( data, offsetNormals, 4 * nElements ); 516 | var materialIndexBuffer = new Uint16Array( data, offsetMaterials, nElements ); 517 | 518 | for ( i = 0; i < nElements; i ++ ) { 519 | 520 | a = vertexIndexBuffer[ i * 4 ]; 521 | b = vertexIndexBuffer[ i * 4 + 1 ]; 522 | c = vertexIndexBuffer[ i * 4 + 2 ]; 523 | d = vertexIndexBuffer[ i * 4 + 3 ]; 524 | 525 | na = normalIndexBuffer[ i * 4 ]; 526 | nb = normalIndexBuffer[ i * 4 + 1 ]; 527 | nc = normalIndexBuffer[ i * 4 + 2 ]; 528 | nd = normalIndexBuffer[ i * 4 + 3 ]; 529 | 530 | m = materialIndexBuffer[ i ]; 531 | 532 | var nax = normals[ na * 3 ], 533 | nay = normals[ na * 3 + 1 ], 534 | naz = normals[ na * 3 + 2 ], 535 | 536 | nbx = normals[ nb * 3 ], 537 | nby = normals[ nb * 3 + 1 ], 538 | nbz = normals[ nb * 3 + 2 ], 539 | 540 | ncx = normals[ nc * 3 ], 541 | ncy = normals[ nc * 3 + 1 ], 542 | ncz = normals[ nc * 3 + 2 ], 543 | 544 | ndx = normals[ nd * 3 ], 545 | ndy = normals[ nd * 3 + 1 ], 546 | ndz = normals[ nd * 3 + 2 ]; 547 | 548 | scope.faces.push( new THREE.Face3( a, b, d, [ 549 | new THREE.Vector3( nax, nay, naz ), 550 | new THREE.Vector3( nbx, nby, nbz ), 551 | new THREE.Vector3( ndx, ndy, ndz ) 552 | ], null, m ) ); 553 | 554 | scope.faces.push( new THREE.Face3( b, c, d, [ 555 | new THREE.Vector3( nbx, nby, nbz ), 556 | new THREE.Vector3( ncx, ncy, ncz ), 557 | new THREE.Vector3( ndx, ndy, ndz ) 558 | ], null, m ) ); 559 | 560 | } 561 | 562 | } 563 | 564 | function init_triangles_flat( start ) { 565 | 566 | var nElements = md.ntri_flat; 567 | 568 | if ( nElements ) { 569 | 570 | var offsetMaterials = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; 571 | init_faces3_flat( nElements, start, offsetMaterials ); 572 | 573 | } 574 | 575 | } 576 | 577 | function init_triangles_flat_uv( start ) { 578 | 579 | var nElements = md.ntri_flat_uv; 580 | 581 | if ( nElements ) { 582 | 583 | var offsetUvs = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; 584 | var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; 585 | 586 | init_faces3_flat( nElements, start, offsetMaterials ); 587 | init_uvs3( nElements, offsetUvs ); 588 | 589 | } 590 | 591 | } 592 | 593 | function init_triangles_smooth( start ) { 594 | 595 | var nElements = md.ntri_smooth; 596 | 597 | if ( nElements ) { 598 | 599 | var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; 600 | var offsetMaterials = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; 601 | 602 | init_faces3_smooth( nElements, start, offsetNormals, offsetMaterials ); 603 | 604 | } 605 | 606 | } 607 | 608 | function init_triangles_smooth_uv( start ) { 609 | 610 | var nElements = md.ntri_smooth_uv; 611 | 612 | if ( nElements ) { 613 | 614 | var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; 615 | var offsetUvs = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; 616 | var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 3; 617 | 618 | init_faces3_smooth( nElements, start, offsetNormals, offsetMaterials ); 619 | init_uvs3( nElements, offsetUvs ); 620 | 621 | } 622 | 623 | } 624 | 625 | function init_quads_flat( start ) { 626 | 627 | var nElements = md.nquad_flat; 628 | 629 | if ( nElements ) { 630 | 631 | var offsetMaterials = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; 632 | init_faces4_flat( nElements, start, offsetMaterials ); 633 | 634 | } 635 | 636 | } 637 | 638 | function init_quads_flat_uv( start ) { 639 | 640 | var nElements = md.nquad_flat_uv; 641 | 642 | if ( nElements ) { 643 | 644 | var offsetUvs = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; 645 | var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; 646 | 647 | init_faces4_flat( nElements, start, offsetMaterials ); 648 | init_uvs4( nElements, offsetUvs ); 649 | 650 | } 651 | 652 | } 653 | 654 | function init_quads_smooth( start ) { 655 | 656 | var nElements = md.nquad_smooth; 657 | 658 | if ( nElements ) { 659 | 660 | var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; 661 | var offsetMaterials = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; 662 | 663 | init_faces4_smooth( nElements, start, offsetNormals, offsetMaterials ); 664 | 665 | } 666 | 667 | } 668 | 669 | function init_quads_smooth_uv( start ) { 670 | 671 | var nElements = md.nquad_smooth_uv; 672 | 673 | if ( nElements ) { 674 | 675 | var offsetNormals = start + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; 676 | var offsetUvs = offsetNormals + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; 677 | var offsetMaterials = offsetUvs + nElements * Uint32Array.BYTES_PER_ELEMENT * 4; 678 | 679 | init_faces4_smooth( nElements, start, offsetNormals, offsetMaterials ); 680 | init_uvs4( nElements, offsetUvs ); 681 | 682 | } 683 | 684 | } 685 | 686 | }; 687 | 688 | Model.prototype = Object.create( THREE.Geometry.prototype ); 689 | Model.prototype.constructor = Model; 690 | 691 | var geometry = new Model( texturePath ); 692 | var materials = THREE.Loader.prototype.initMaterials( jsonMaterials, texturePath, this.crossOrigin ); 693 | 694 | callback( geometry, materials ); 695 | 696 | } 697 | 698 | }; 699 | -------------------------------------------------------------------------------- /vendor/OrbitControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author qiao / https://github.com/qiao 3 | * @author mrdoob / http://mrdoob.com 4 | * @author alteredq / http://alteredqualia.com/ 5 | * @author WestLangley / http://github.com/WestLangley 6 | * @author erich666 / http://erichaines.com 7 | */ 8 | 9 | // This set of controls performs orbiting, dollying (zooming), and panning. 10 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). 11 | // 12 | // Orbit - left mouse / touch: one finger move 13 | // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish 14 | // Pan - right mouse, or arrow keys / touch: three finger swipe 15 | 16 | THREE.OrbitControls = function ( object, domElement ) { 17 | 18 | this.object = object; 19 | 20 | this.domElement = ( domElement !== undefined ) ? domElement : document; 21 | 22 | // Set to false to disable this control 23 | this.enabled = true; 24 | 25 | // "target" sets the location of focus, where the object orbits around 26 | this.target = new THREE.Vector3(); 27 | 28 | // How far you can dolly in and out ( PerspectiveCamera only ) 29 | this.minDistance = 0; 30 | this.maxDistance = Infinity; 31 | 32 | // How far you can zoom in and out ( OrthographicCamera only ) 33 | this.minZoom = 0; 34 | this.maxZoom = Infinity; 35 | 36 | // How far you can orbit vertically, upper and lower limits. 37 | // Range is 0 to Math.PI radians. 38 | this.minPolarAngle = 0; // radians 39 | this.maxPolarAngle = Math.PI; // radians 40 | 41 | // How far you can orbit horizontally, upper and lower limits. 42 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. 43 | this.minAzimuthAngle = - Infinity; // radians 44 | this.maxAzimuthAngle = Infinity; // radians 45 | 46 | // Set to true to enable damping (inertia) 47 | // If damping is enabled, you must call controls.update() in your animation loop 48 | this.enableDamping = false; 49 | this.dampingFactor = 0.25; 50 | 51 | // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. 52 | // Set to false to disable zooming 53 | this.enableZoom = true; 54 | this.zoomSpeed = 1.0; 55 | 56 | // Set to false to disable rotating 57 | this.enableRotate = true; 58 | this.rotateSpeed = 1.0; 59 | 60 | // Set to false to disable panning 61 | this.enablePan = true; 62 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push 63 | 64 | // Set to true to automatically rotate around the target 65 | // If auto-rotate is enabled, you must call controls.update() in your animation loop 66 | this.autoRotate = false; 67 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 68 | 69 | // Set to false to disable use of the keys 70 | this.enableKeys = true; 71 | 72 | // The four arrow keys 73 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; 74 | 75 | // Mouse buttons 76 | this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; 77 | 78 | // for reset 79 | this.target0 = this.target.clone(); 80 | this.position0 = this.object.position.clone(); 81 | this.zoom0 = this.object.zoom; 82 | 83 | // 84 | // public methods 85 | // 86 | 87 | this.getPolarAngle = function () { 88 | 89 | return spherical.phi; 90 | 91 | }; 92 | 93 | this.getAzimuthalAngle = function () { 94 | 95 | return spherical.theta; 96 | 97 | }; 98 | 99 | this.saveState = function () { 100 | 101 | scope.target0.copy( scope.target ); 102 | scope.position0.copy( scope.object.position ); 103 | scope.zoom0 = scope.object.zoom; 104 | 105 | }; 106 | 107 | this.reset = function () { 108 | 109 | scope.target.copy( scope.target0 ); 110 | scope.object.position.copy( scope.position0 ); 111 | scope.object.zoom = scope.zoom0; 112 | 113 | scope.object.updateProjectionMatrix(); 114 | scope.dispatchEvent( changeEvent ); 115 | 116 | scope.update(); 117 | 118 | state = STATE.NONE; 119 | 120 | }; 121 | 122 | // this method is exposed, but perhaps it would be better if we can make it private... 123 | this.update = function () { 124 | 125 | var offset = new THREE.Vector3(); 126 | 127 | // so camera.up is the orbit axis 128 | var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); 129 | var quatInverse = quat.clone().inverse(); 130 | 131 | var lastPosition = new THREE.Vector3(); 132 | var lastQuaternion = new THREE.Quaternion(); 133 | 134 | return function update() { 135 | 136 | var position = scope.object.position; 137 | 138 | offset.copy( position ).sub( scope.target ); 139 | 140 | // rotate offset to "y-axis-is-up" space 141 | offset.applyQuaternion( quat ); 142 | 143 | // angle from z-axis around y-axis 144 | spherical.setFromVector3( offset ); 145 | 146 | if ( scope.autoRotate && state === STATE.NONE ) { 147 | 148 | rotateLeft( getAutoRotationAngle() ); 149 | 150 | } 151 | 152 | spherical.theta += sphericalDelta.theta; 153 | spherical.phi += sphericalDelta.phi; 154 | 155 | // restrict theta to be between desired limits 156 | spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) ); 157 | 158 | // restrict phi to be between desired limits 159 | spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) ); 160 | 161 | spherical.makeSafe(); 162 | 163 | 164 | spherical.radius *= scale; 165 | 166 | // restrict radius to be between desired limits 167 | spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); 168 | 169 | // move target to panned location 170 | scope.target.add( panOffset ); 171 | 172 | offset.setFromSpherical( spherical ); 173 | 174 | // rotate offset back to "camera-up-vector-is-up" space 175 | offset.applyQuaternion( quatInverse ); 176 | 177 | position.copy( scope.target ).add( offset ); 178 | 179 | scope.object.lookAt( scope.target ); 180 | 181 | if ( scope.enableDamping === true ) { 182 | 183 | sphericalDelta.theta *= ( 1 - scope.dampingFactor ); 184 | sphericalDelta.phi *= ( 1 - scope.dampingFactor ); 185 | 186 | } else { 187 | 188 | sphericalDelta.set( 0, 0, 0 ); 189 | 190 | } 191 | 192 | scale = 1; 193 | panOffset.set( 0, 0, 0 ); 194 | 195 | // update condition is: 196 | // min(camera displacement, camera rotation in radians)^2 > EPS 197 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8 198 | 199 | if ( zoomChanged || 200 | lastPosition.distanceToSquared( scope.object.position ) > EPS || 201 | 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { 202 | 203 | scope.dispatchEvent( changeEvent ); 204 | 205 | lastPosition.copy( scope.object.position ); 206 | lastQuaternion.copy( scope.object.quaternion ); 207 | zoomChanged = false; 208 | 209 | return true; 210 | 211 | } 212 | 213 | return false; 214 | 215 | }; 216 | 217 | }(); 218 | 219 | this.dispose = function () { 220 | 221 | scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false ); 222 | scope.domElement.removeEventListener( 'mousedown', onMouseDown, false ); 223 | scope.domElement.removeEventListener( 'wheel', onMouseWheel, false ); 224 | 225 | scope.domElement.removeEventListener( 'touchstart', onTouchStart, false ); 226 | scope.domElement.removeEventListener( 'touchend', onTouchEnd, false ); 227 | scope.domElement.removeEventListener( 'touchmove', onTouchMove, false ); 228 | 229 | document.removeEventListener( 'mousemove', onMouseMove, false ); 230 | document.removeEventListener( 'mouseup', onMouseUp, false ); 231 | 232 | window.removeEventListener( 'keydown', onKeyDown, false ); 233 | 234 | //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? 235 | 236 | }; 237 | 238 | // 239 | // internals 240 | // 241 | 242 | var scope = this; 243 | 244 | var changeEvent = { type: 'change' }; 245 | var startEvent = { type: 'start' }; 246 | var endEvent = { type: 'end' }; 247 | 248 | var STATE = { NONE: - 1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY: 4, TOUCH_PAN: 5 }; 249 | 250 | var state = STATE.NONE; 251 | 252 | var EPS = 0.000001; 253 | 254 | // current position in spherical coordinates 255 | var spherical = new THREE.Spherical(); 256 | var sphericalDelta = new THREE.Spherical(); 257 | 258 | var scale = 1; 259 | var panOffset = new THREE.Vector3(); 260 | var zoomChanged = false; 261 | 262 | var rotateStart = new THREE.Vector2(); 263 | var rotateEnd = new THREE.Vector2(); 264 | var rotateDelta = new THREE.Vector2(); 265 | 266 | var panStart = new THREE.Vector2(); 267 | var panEnd = new THREE.Vector2(); 268 | var panDelta = new THREE.Vector2(); 269 | 270 | var dollyStart = new THREE.Vector2(); 271 | var dollyEnd = new THREE.Vector2(); 272 | var dollyDelta = new THREE.Vector2(); 273 | 274 | function getAutoRotationAngle() { 275 | 276 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; 277 | 278 | } 279 | 280 | function getZoomScale() { 281 | 282 | return Math.pow( 0.95, scope.zoomSpeed ); 283 | 284 | } 285 | 286 | function rotateLeft( angle ) { 287 | 288 | sphericalDelta.theta -= angle; 289 | 290 | } 291 | 292 | function rotateUp( angle ) { 293 | 294 | sphericalDelta.phi -= angle; 295 | 296 | } 297 | 298 | var panLeft = function () { 299 | 300 | var v = new THREE.Vector3(); 301 | 302 | return function panLeft( distance, objectMatrix ) { 303 | 304 | v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix 305 | v.multiplyScalar( - distance ); 306 | 307 | panOffset.add( v ); 308 | 309 | }; 310 | 311 | }(); 312 | 313 | var panUp = function () { 314 | 315 | var v = new THREE.Vector3(); 316 | 317 | return function panUp( distance, objectMatrix ) { 318 | 319 | v.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix 320 | v.multiplyScalar( distance ); 321 | 322 | panOffset.add( v ); 323 | 324 | }; 325 | 326 | }(); 327 | 328 | // deltaX and deltaY are in pixels; right and down are positive 329 | var pan = function () { 330 | 331 | var offset = new THREE.Vector3(); 332 | 333 | return function pan( deltaX, deltaY ) { 334 | 335 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 336 | 337 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 338 | 339 | // perspective 340 | var position = scope.object.position; 341 | offset.copy( position ).sub( scope.target ); 342 | var targetDistance = offset.length(); 343 | 344 | // half of the fov is center to top of screen 345 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); 346 | 347 | // we actually don't use screenWidth, since perspective camera is fixed to screen height 348 | panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix ); 349 | panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix ); 350 | 351 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 352 | 353 | // orthographic 354 | panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix ); 355 | panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix ); 356 | 357 | } else { 358 | 359 | // camera neither orthographic nor perspective 360 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); 361 | scope.enablePan = false; 362 | 363 | } 364 | 365 | }; 366 | 367 | }(); 368 | 369 | function dollyIn( dollyScale ) { 370 | 371 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 372 | 373 | scale /= dollyScale; 374 | 375 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 376 | 377 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); 378 | scope.object.updateProjectionMatrix(); 379 | zoomChanged = true; 380 | 381 | } else { 382 | 383 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); 384 | scope.enableZoom = false; 385 | 386 | } 387 | 388 | } 389 | 390 | function dollyOut( dollyScale ) { 391 | 392 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 393 | 394 | scale *= dollyScale; 395 | 396 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 397 | 398 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); 399 | scope.object.updateProjectionMatrix(); 400 | zoomChanged = true; 401 | 402 | } else { 403 | 404 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); 405 | scope.enableZoom = false; 406 | 407 | } 408 | 409 | } 410 | 411 | // 412 | // event callbacks - update the object state 413 | // 414 | 415 | function handleMouseDownRotate( event ) { 416 | 417 | //console.log( 'handleMouseDownRotate' ); 418 | 419 | rotateStart.set( event.clientX, event.clientY ); 420 | 421 | } 422 | 423 | function handleMouseDownDolly( event ) { 424 | 425 | //console.log( 'handleMouseDownDolly' ); 426 | 427 | dollyStart.set( event.clientX, event.clientY ); 428 | 429 | } 430 | 431 | function handleMouseDownPan( event ) { 432 | 433 | //console.log( 'handleMouseDownPan' ); 434 | 435 | panStart.set( event.clientX, event.clientY ); 436 | 437 | } 438 | 439 | function handleMouseMoveRotate( event ) { 440 | 441 | //console.log( 'handleMouseMoveRotate' ); 442 | 443 | rotateEnd.set( event.clientX, event.clientY ); 444 | rotateDelta.subVectors( rotateEnd, rotateStart ); 445 | 446 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 447 | 448 | // rotating across whole screen goes 360 degrees around 449 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); 450 | 451 | // rotating up and down along whole screen attempts to go 360, but limited to 180 452 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); 453 | 454 | rotateStart.copy( rotateEnd ); 455 | 456 | scope.update(); 457 | 458 | } 459 | 460 | function handleMouseMoveDolly( event ) { 461 | 462 | //console.log( 'handleMouseMoveDolly' ); 463 | 464 | dollyEnd.set( event.clientX, event.clientY ); 465 | 466 | dollyDelta.subVectors( dollyEnd, dollyStart ); 467 | 468 | if ( dollyDelta.y > 0 ) { 469 | 470 | dollyIn( getZoomScale() ); 471 | 472 | } else if ( dollyDelta.y < 0 ) { 473 | 474 | dollyOut( getZoomScale() ); 475 | 476 | } 477 | 478 | dollyStart.copy( dollyEnd ); 479 | 480 | scope.update(); 481 | 482 | } 483 | 484 | function handleMouseMovePan( event ) { 485 | 486 | //console.log( 'handleMouseMovePan' ); 487 | 488 | panEnd.set( event.clientX, event.clientY ); 489 | 490 | panDelta.subVectors( panEnd, panStart ); 491 | 492 | pan( panDelta.x, panDelta.y ); 493 | 494 | panStart.copy( panEnd ); 495 | 496 | scope.update(); 497 | 498 | } 499 | 500 | function handleMouseUp( event ) { 501 | 502 | // console.log( 'handleMouseUp' ); 503 | 504 | } 505 | 506 | function handleMouseWheel( event ) { 507 | 508 | // console.log( 'handleMouseWheel' ); 509 | 510 | if ( event.deltaY < 0 ) { 511 | 512 | dollyOut( getZoomScale() ); 513 | 514 | } else if ( event.deltaY > 0 ) { 515 | 516 | dollyIn( getZoomScale() ); 517 | 518 | } 519 | 520 | scope.update(); 521 | 522 | } 523 | 524 | function handleKeyDown( event ) { 525 | 526 | //console.log( 'handleKeyDown' ); 527 | 528 | switch ( event.keyCode ) { 529 | 530 | case scope.keys.UP: 531 | pan( 0, scope.keyPanSpeed ); 532 | scope.update(); 533 | break; 534 | 535 | case scope.keys.BOTTOM: 536 | pan( 0, - scope.keyPanSpeed ); 537 | scope.update(); 538 | break; 539 | 540 | case scope.keys.LEFT: 541 | pan( scope.keyPanSpeed, 0 ); 542 | scope.update(); 543 | break; 544 | 545 | case scope.keys.RIGHT: 546 | pan( - scope.keyPanSpeed, 0 ); 547 | scope.update(); 548 | break; 549 | 550 | } 551 | 552 | } 553 | 554 | function handleTouchStartRotate( event ) { 555 | 556 | //console.log( 'handleTouchStartRotate' ); 557 | 558 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 559 | 560 | } 561 | 562 | function handleTouchStartDolly( event ) { 563 | 564 | //console.log( 'handleTouchStartDolly' ); 565 | 566 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 567 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 568 | 569 | var distance = Math.sqrt( dx * dx + dy * dy ); 570 | 571 | dollyStart.set( 0, distance ); 572 | 573 | } 574 | 575 | function handleTouchStartPan( event ) { 576 | 577 | //console.log( 'handleTouchStartPan' ); 578 | 579 | panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 580 | 581 | } 582 | 583 | function handleTouchMoveRotate( event ) { 584 | 585 | //console.log( 'handleTouchMoveRotate' ); 586 | 587 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 588 | rotateDelta.subVectors( rotateEnd, rotateStart ); 589 | 590 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 591 | 592 | // rotating across whole screen goes 360 degrees around 593 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); 594 | 595 | // rotating up and down along whole screen attempts to go 360, but limited to 180 596 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); 597 | 598 | rotateStart.copy( rotateEnd ); 599 | 600 | scope.update(); 601 | 602 | } 603 | 604 | function handleTouchMoveDolly( event ) { 605 | 606 | //console.log( 'handleTouchMoveDolly' ); 607 | 608 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 609 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 610 | 611 | var distance = Math.sqrt( dx * dx + dy * dy ); 612 | 613 | dollyEnd.set( 0, distance ); 614 | 615 | dollyDelta.subVectors( dollyEnd, dollyStart ); 616 | 617 | if ( dollyDelta.y > 0 ) { 618 | 619 | dollyOut( getZoomScale() ); 620 | 621 | } else if ( dollyDelta.y < 0 ) { 622 | 623 | dollyIn( getZoomScale() ); 624 | 625 | } 626 | 627 | dollyStart.copy( dollyEnd ); 628 | 629 | scope.update(); 630 | 631 | } 632 | 633 | function handleTouchMovePan( event ) { 634 | 635 | //console.log( 'handleTouchMovePan' ); 636 | 637 | panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 638 | 639 | panDelta.subVectors( panEnd, panStart ); 640 | 641 | pan( panDelta.x, panDelta.y ); 642 | 643 | panStart.copy( panEnd ); 644 | 645 | scope.update(); 646 | 647 | } 648 | 649 | function handleTouchEnd( event ) { 650 | 651 | //console.log( 'handleTouchEnd' ); 652 | 653 | } 654 | 655 | // 656 | // event handlers - FSM: listen for events and reset state 657 | // 658 | 659 | function onMouseDown( event ) { 660 | 661 | if ( scope.enabled === false ) return; 662 | 663 | event.preventDefault(); 664 | 665 | if ( event.button === scope.mouseButtons.ORBIT ) { 666 | 667 | if ( scope.enableRotate === false ) return; 668 | 669 | handleMouseDownRotate( event ); 670 | 671 | state = STATE.ROTATE; 672 | 673 | } else if ( event.button === scope.mouseButtons.ZOOM ) { 674 | 675 | if ( scope.enableZoom === false ) return; 676 | 677 | handleMouseDownDolly( event ); 678 | 679 | state = STATE.DOLLY; 680 | 681 | } else if ( event.button === scope.mouseButtons.PAN ) { 682 | 683 | if ( scope.enablePan === false ) return; 684 | 685 | handleMouseDownPan( event ); 686 | 687 | state = STATE.PAN; 688 | 689 | } 690 | 691 | if ( state !== STATE.NONE ) { 692 | 693 | document.addEventListener( 'mousemove', onMouseMove, false ); 694 | document.addEventListener( 'mouseup', onMouseUp, false ); 695 | 696 | scope.dispatchEvent( startEvent ); 697 | 698 | } 699 | 700 | } 701 | 702 | function onMouseMove( event ) { 703 | 704 | if ( scope.enabled === false ) return; 705 | 706 | event.preventDefault(); 707 | 708 | if ( state === STATE.ROTATE ) { 709 | 710 | if ( scope.enableRotate === false ) return; 711 | 712 | handleMouseMoveRotate( event ); 713 | 714 | } else if ( state === STATE.DOLLY ) { 715 | 716 | if ( scope.enableZoom === false ) return; 717 | 718 | handleMouseMoveDolly( event ); 719 | 720 | } else if ( state === STATE.PAN ) { 721 | 722 | if ( scope.enablePan === false ) return; 723 | 724 | handleMouseMovePan( event ); 725 | 726 | } 727 | 728 | } 729 | 730 | function onMouseUp( event ) { 731 | 732 | if ( scope.enabled === false ) return; 733 | 734 | handleMouseUp( event ); 735 | 736 | document.removeEventListener( 'mousemove', onMouseMove, false ); 737 | document.removeEventListener( 'mouseup', onMouseUp, false ); 738 | 739 | scope.dispatchEvent( endEvent ); 740 | 741 | state = STATE.NONE; 742 | 743 | } 744 | 745 | function onMouseWheel( event ) { 746 | 747 | if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return; 748 | 749 | event.preventDefault(); 750 | event.stopPropagation(); 751 | 752 | handleMouseWheel( event ); 753 | 754 | scope.dispatchEvent( startEvent ); // not sure why these are here... 755 | scope.dispatchEvent( endEvent ); 756 | 757 | } 758 | 759 | function onKeyDown( event ) { 760 | 761 | if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; 762 | 763 | handleKeyDown( event ); 764 | 765 | } 766 | 767 | function onTouchStart( event ) { 768 | 769 | if ( scope.enabled === false ) return; 770 | 771 | switch ( event.touches.length ) { 772 | 773 | case 1: // one-fingered touch: rotate 774 | 775 | if ( scope.enableRotate === false ) return; 776 | 777 | handleTouchStartRotate( event ); 778 | 779 | state = STATE.TOUCH_ROTATE; 780 | 781 | break; 782 | 783 | case 2: // two-fingered touch: dolly 784 | 785 | if ( scope.enableZoom === false ) return; 786 | 787 | handleTouchStartDolly( event ); 788 | 789 | state = STATE.TOUCH_DOLLY; 790 | 791 | break; 792 | 793 | case 3: // three-fingered touch: pan 794 | 795 | if ( scope.enablePan === false ) return; 796 | 797 | handleTouchStartPan( event ); 798 | 799 | state = STATE.TOUCH_PAN; 800 | 801 | break; 802 | 803 | default: 804 | 805 | state = STATE.NONE; 806 | 807 | } 808 | 809 | if ( state !== STATE.NONE ) { 810 | 811 | scope.dispatchEvent( startEvent ); 812 | 813 | } 814 | 815 | } 816 | 817 | function onTouchMove( event ) { 818 | 819 | if ( scope.enabled === false ) return; 820 | 821 | event.preventDefault(); 822 | event.stopPropagation(); 823 | 824 | switch ( event.touches.length ) { 825 | 826 | case 1: // one-fingered touch: rotate 827 | 828 | if ( scope.enableRotate === false ) return; 829 | if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?... 830 | 831 | handleTouchMoveRotate( event ); 832 | 833 | break; 834 | 835 | case 2: // two-fingered touch: dolly 836 | 837 | if ( scope.enableZoom === false ) return; 838 | if ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?... 839 | 840 | handleTouchMoveDolly( event ); 841 | 842 | break; 843 | 844 | case 3: // three-fingered touch: pan 845 | 846 | if ( scope.enablePan === false ) return; 847 | if ( state !== STATE.TOUCH_PAN ) return; // is this needed?... 848 | 849 | handleTouchMovePan( event ); 850 | 851 | break; 852 | 853 | default: 854 | 855 | state = STATE.NONE; 856 | 857 | } 858 | 859 | } 860 | 861 | function onTouchEnd( event ) { 862 | 863 | if ( scope.enabled === false ) return; 864 | 865 | handleTouchEnd( event ); 866 | 867 | scope.dispatchEvent( endEvent ); 868 | 869 | state = STATE.NONE; 870 | 871 | } 872 | 873 | function onContextMenu( event ) { 874 | 875 | event.preventDefault(); 876 | 877 | } 878 | 879 | // 880 | 881 | scope.domElement.addEventListener( 'contextmenu', onContextMenu, false ); 882 | 883 | scope.domElement.addEventListener( 'mousedown', onMouseDown, false ); 884 | scope.domElement.addEventListener( 'wheel', onMouseWheel, false ); 885 | 886 | scope.domElement.addEventListener( 'touchstart', onTouchStart, false ); 887 | scope.domElement.addEventListener( 'touchend', onTouchEnd, false ); 888 | scope.domElement.addEventListener( 'touchmove', onTouchMove, false ); 889 | 890 | window.addEventListener( 'keydown', onKeyDown, false ); 891 | 892 | // force an update at start 893 | 894 | this.update(); 895 | 896 | }; 897 | 898 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 899 | THREE.OrbitControls.prototype.constructor = THREE.OrbitControls; 900 | 901 | Object.defineProperties( THREE.OrbitControls.prototype, { 902 | 903 | center: { 904 | 905 | get: function () { 906 | 907 | console.warn( 'THREE.OrbitControls: .center has been renamed to .target' ); 908 | return this.target; 909 | 910 | } 911 | 912 | }, 913 | 914 | // backward compatibility 915 | 916 | noZoom: { 917 | 918 | get: function () { 919 | 920 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); 921 | return ! this.enableZoom; 922 | 923 | }, 924 | 925 | set: function ( value ) { 926 | 927 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); 928 | this.enableZoom = ! value; 929 | 930 | } 931 | 932 | }, 933 | 934 | noRotate: { 935 | 936 | get: function () { 937 | 938 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); 939 | return ! this.enableRotate; 940 | 941 | }, 942 | 943 | set: function ( value ) { 944 | 945 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); 946 | this.enableRotate = ! value; 947 | 948 | } 949 | 950 | }, 951 | 952 | noPan: { 953 | 954 | get: function () { 955 | 956 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); 957 | return ! this.enablePan; 958 | 959 | }, 960 | 961 | set: function ( value ) { 962 | 963 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); 964 | this.enablePan = ! value; 965 | 966 | } 967 | 968 | }, 969 | 970 | noKeys: { 971 | 972 | get: function () { 973 | 974 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); 975 | return ! this.enableKeys; 976 | 977 | }, 978 | 979 | set: function ( value ) { 980 | 981 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); 982 | this.enableKeys = ! value; 983 | 984 | } 985 | 986 | }, 987 | 988 | staticMoving: { 989 | 990 | get: function () { 991 | 992 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); 993 | return ! this.enableDamping; 994 | 995 | }, 996 | 997 | set: function ( value ) { 998 | 999 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); 1000 | this.enableDamping = ! value; 1001 | 1002 | } 1003 | 1004 | }, 1005 | 1006 | dynamicDampingFactor: { 1007 | 1008 | get: function () { 1009 | 1010 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); 1011 | return this.dampingFactor; 1012 | 1013 | }, 1014 | 1015 | set: function ( value ) { 1016 | 1017 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); 1018 | this.dampingFactor = value; 1019 | 1020 | } 1021 | 1022 | } 1023 | 1024 | } ); 1025 | -------------------------------------------------------------------------------- /vendor/THREE.MeshLine.js: -------------------------------------------------------------------------------- 1 | ;(function() { 2 | 3 | "use strict"; 4 | 5 | var root = this 6 | 7 | var has_require = typeof require !== 'undefined' 8 | 9 | var THREE = root.THREE || has_require && require('three') 10 | if( !THREE ) 11 | throw new Error( 'MeshLine requires three.js' ) 12 | 13 | function MeshLine() { 14 | 15 | this.positions = []; 16 | 17 | this.previous = []; 18 | this.next = []; 19 | this.side = []; 20 | this.width = []; 21 | this.indices_array = []; 22 | this.uvs = []; 23 | this.counters = []; 24 | this.geometry = new THREE.BufferGeometry(); 25 | 26 | this.widthCallback = null; 27 | 28 | } 29 | 30 | MeshLine.prototype.setGeometry = function( g, c ) { 31 | 32 | this.widthCallback = c; 33 | 34 | this.positions = []; 35 | this.counters = []; 36 | 37 | if( g instanceof THREE.Geometry ) { 38 | for( var j = 0; j < g.vertices.length; j++ ) { 39 | var v = g.vertices[ j ]; 40 | var c = j/g.vertices.length; 41 | this.positions.push( v.x, v.y, v.z ); 42 | this.positions.push( v.x, v.y, v.z ); 43 | this.counters.push(c); 44 | this.counters.push(c); 45 | } 46 | } 47 | 48 | if( g instanceof THREE.BufferGeometry ) { 49 | // read attribute positions ? 50 | } 51 | 52 | if( g instanceof Float32Array || g instanceof Array ) { 53 | for( var j = 0; j < g.length; j += 3 ) { 54 | var c = j/g.length; 55 | this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] ); 56 | this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] ); 57 | this.counters.push(c); 58 | this.counters.push(c); 59 | } 60 | } 61 | 62 | this.process(); 63 | 64 | } 65 | 66 | MeshLine.prototype.compareV3 = function( a, b ) { 67 | 68 | var aa = a * 6; 69 | var ab = b * 6; 70 | return ( this.positions[ aa ] === this.positions[ ab ] ) && ( this.positions[ aa + 1 ] === this.positions[ ab + 1 ] ) && ( this.positions[ aa + 2 ] === this.positions[ ab + 2 ] ); 71 | 72 | } 73 | 74 | MeshLine.prototype.copyV3 = function( a ) { 75 | 76 | var aa = a * 6; 77 | return [ this.positions[ aa ], this.positions[ aa + 1 ], this.positions[ aa + 2 ] ]; 78 | 79 | } 80 | 81 | MeshLine.prototype.process = function() { 82 | 83 | var l = this.positions.length / 6; 84 | 85 | this.previous = []; 86 | this.next = []; 87 | this.side = []; 88 | this.width = []; 89 | this.indices_array = []; 90 | this.uvs = []; 91 | 92 | for( var j = 0; j < l; j++ ) { 93 | this.side.push( 1 ); 94 | this.side.push( -1 ); 95 | } 96 | 97 | var w; 98 | for( var j = 0; j < l; j++ ) { 99 | if( this.widthCallback ) w = this.widthCallback( j / ( l -1 ) ); 100 | else w = 1; 101 | this.width.push( w ); 102 | this.width.push( w ); 103 | } 104 | 105 | for( var j = 0; j < l; j++ ) { 106 | this.uvs.push( j / ( l - 1 ), 0 ); 107 | this.uvs.push( j / ( l - 1 ), 1 ); 108 | } 109 | 110 | var v; 111 | 112 | if( this.compareV3( 0, l - 1 ) ){ 113 | v = this.copyV3( l - 2 ); 114 | } else { 115 | v = this.copyV3( 0 ); 116 | } 117 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 118 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 119 | for( var j = 0; j < l - 1; j++ ) { 120 | v = this.copyV3( j ); 121 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 122 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 123 | } 124 | 125 | for( var j = 1; j < l; j++ ) { 126 | v = this.copyV3( j ); 127 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 128 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 129 | } 130 | 131 | if( this.compareV3( l - 1, 0 ) ){ 132 | v = this.copyV3( 1 ); 133 | } else { 134 | v = this.copyV3( l - 1 ); 135 | } 136 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 137 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 138 | 139 | for( var j = 0; j < l - 1; j++ ) { 140 | var n = j * 2; 141 | this.indices_array.push( n, n + 1, n + 2 ); 142 | this.indices_array.push( n + 2, n + 1, n + 3 ); 143 | } 144 | 145 | if (!this.attributes) { 146 | this.attributes = { 147 | position: new THREE.BufferAttribute( new Float32Array( this.positions ), 3 ), 148 | previous: new THREE.BufferAttribute( new Float32Array( this.previous ), 3 ), 149 | next: new THREE.BufferAttribute( new Float32Array( this.next ), 3 ), 150 | side: new THREE.BufferAttribute( new Float32Array( this.side ), 1 ), 151 | width: new THREE.BufferAttribute( new Float32Array( this.width ), 1 ), 152 | uv: new THREE.BufferAttribute( new Float32Array( this.uvs ), 2 ), 153 | index: new THREE.BufferAttribute( new Uint16Array( this.indices_array ), 1 ), 154 | counters: new THREE.BufferAttribute( new Float32Array( this.counters ), 1 ) 155 | } 156 | } else { 157 | this.attributes.position.copyArray(new Float32Array(this.positions)); 158 | this.attributes.position.needsUpdate = true; 159 | this.attributes.previous.copyArray(new Float32Array(this.previous)); 160 | this.attributes.previous.needsUpdate = true; 161 | this.attributes.next.copyArray(new Float32Array(this.next)); 162 | this.attributes.next.needsUpdate = true; 163 | this.attributes.side.copyArray(new Float32Array(this.side)); 164 | this.attributes.side.needsUpdate = true; 165 | this.attributes.width.copyArray(new Float32Array(this.width)); 166 | this.attributes.width.needsUpdate = true; 167 | this.attributes.uv.copyArray(new Float32Array(this.uvs)); 168 | this.attributes.uv.needsUpdate = true; 169 | this.attributes.index.copyArray(new Uint16Array(this.indices_array)); 170 | this.attributes.index.needsUpdate = true; 171 | } 172 | 173 | this.geometry.addAttribute( 'position', this.attributes.position ); 174 | this.geometry.addAttribute( 'previous', this.attributes.previous ); 175 | this.geometry.addAttribute( 'next', this.attributes.next ); 176 | this.geometry.addAttribute( 'side', this.attributes.side ); 177 | this.geometry.addAttribute( 'width', this.attributes.width ); 178 | this.geometry.addAttribute( 'uv', this.attributes.uv ); 179 | this.geometry.addAttribute( 'counters', this.attributes.counters ); 180 | 181 | this.geometry.setIndex( this.attributes.index ); 182 | 183 | } 184 | 185 | function memcpy (src, srcOffset, dst, dstOffset, length) { 186 | var i 187 | 188 | src = src.subarray || src.slice ? src : src.buffer 189 | dst = dst.subarray || dst.slice ? dst : dst.buffer 190 | 191 | src = srcOffset ? src.subarray ? 192 | src.subarray(srcOffset, length && srcOffset + length) : 193 | src.slice(srcOffset, length && srcOffset + length) : src 194 | 195 | if (dst.set) { 196 | dst.set(src, dstOffset) 197 | } else { 198 | for (i=0; i