├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── aframeenvironment.gif ├── assets.blend └── how_to_add_new_dressing_geometry.png ├── dist ├── aframe-environment-component.js └── aframe-environment-component.min.js ├── index.html ├── index.js ├── package-lock.json ├── package.json ├── tests └── index.html └── tools ├── extrudeEditor.html └── latheEditor.html /.gitattributes: -------------------------------------------------------------------------------- 1 | *.blend binary 2 | *.jpg binary 3 | *.png binary 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Diego F. Goberna 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aframe-environment-component 2 | 3 | A simple way of setting up a whole basic environment for your 4 | [A-Frame](http://aframe.io) VR scene. 5 | 6 | ![gif](https://github.com/feiss/aframe-environment-component/blob/master/assets/aframeenvironment.gif?raw=true) 7 | 8 | Make sure you are using __A-Frame 1.7.0__ or later. Then just include `aframe-environment-component.js` in your HTML: 9 | 10 | ```html 11 | 12 | ``` 13 | 14 | and add the `environment` component to an entity: 15 | 16 | ```html 17 | 18 | ``` 19 | 20 | That's it! :) 21 | 22 | ## Presets 23 | 24 | The previous code will setup a default scene, but you have a bunch of already predefined presets to choose from, using the `preset` parameter, like this: 25 | 26 | ```html 27 | 28 | ``` 29 | 30 | You can view and try all the presets in the **[aframe-environment-component Test Page](http://supermedium.github.io/aframe-environment-component/)**. The current list of presets are listed in the next section. 31 | 32 | ## Parameters 33 | 34 | Apart from using a preset, you can tweak the environment with many parameters, like this: 35 | 36 | ```html 37 | 38 | ``` 39 | 40 | You can also select a preset but change some of its parameters: 41 | 42 | ```html 43 | 44 | ``` 45 | 46 | This is the list of the available parameters. 47 | 48 | 49 | | Parameter | Default | Description | 50 | | ------------------------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 51 | | **active** | true | Show/hides the component. Use this instead of using the`visible` attribute | 52 | | **preset** | 'default' | Valid values:`none`, `default`, `contact`, `egypt`, `checkerboard`, `forest`, `goaland`, `yavapai`, `goldmine`, `threetowers`, `poison`, `arches`, `tron`, `japan`, `dream`, `volcano`, `starry`, `osiris`, `moon` | 53 | | **seed** | 1 | Seed for randomization. If you don't like the layout of the elements, try another value for the seed. | 54 | | **skyType** | 'atmosphere' | Valid values:`color`, `gradient`, `atmosphere` | 55 | | **skyColor** | | When`skyType` is `color` or `gradient`, it sets the main sky color | 56 | | **horizonColor** | | When`skyType` is `gradient`, it sets the color of the sky near the horizon | 57 | | **lighting** | 'distant' | Valid values:`none`, `distant`, `point`. A hemisphere light and a key light (directional or point) are added to the scene automatically when using the component. Use `none` if you don't want this automatic lighting set being added. The color and intensity are estimated automatically. | 58 | | **shadow** | false | Shadows on/off. Sky light casts shadows on the ground of all those objects with`shadow` component applied | 59 | | **shadowSize** | 10 | Shadows size | 60 | | **lightPosition** | 0 1 -0.2 | Position of the main light. If`skyType` is `atmospheric`, only the orientation matters (is a directional light) and it can turn the scene into night when lowered towards the horizon. | 61 | | **fog** | 0 | Amount of fog (0 = none, 1 = full fog). The color is estimated automatically. | 62 | | **flatShading** | false | Whether to show everything smoothed (false) or polygonal (true). | 63 | | **playArea** | 1 | Radius of the area in the center reserved for the player and the gameplay. The ground is flat in there and no objects are placed inside. | 64 | | **stageSize** | 200 | Environment ground diameter and sky radius. | 65 | | **ground** | 'hills' | Valid values:`none`, `flat`, `hills`, `canyon`, `spikes`, `noise`. Orography style. | 66 | | **groundYScale** | 3 | Maximum height (in meters) of ground's features (hills, mountains, peaks..) | 67 | | **groundTexture** | 'none' | Valid values:`none`, `checkerboard`, `squares`, `walkernoise` | 68 | | **groundColor** | '#553e35' | Main color of the ground | 69 | | **groundColor2** | '#694439' | Secondary color of the ground. Used for textures, ignored if`groundTexture` is `none` | 70 | | **groundDensity** | 64 | Number of divisions of the ground mesh. | 71 | | **groundFrequency** | 10 | Frequency used to generate noise / terrain unevenness on the ground mesh. | 72 | | **dressing** | 'none' | Valid values:`none`, `cubes`, `pyramids`, `cylinders`, `towers`, `mushrooms`, `trees`, `apparatus`, `torii`. Dressing is the term we use here for the set of additional objects that are put on the ground for decoration. | 73 | | **dressingAmount** | 10 | Number of objects used for dressing | 74 | | **dressingColor** | '#795449' | Base color of dressing objects | 75 | | **dressingScale** | 5 | Height (in meters) of dressing objects | 76 | | **dressingVariance** | '1 1 1' | Maximum x,y,z meters to randomize the size and rotation of each dressing object. Use`0 0 0` for no variation in size nor rotation | 77 | | **dressingUniformScale** | true | If`false`, a different value is used for each coordinate x, y, z in the random variance of size. | 78 | | **grid** | 'none' | Valid values:`none`, `1x1`, `2x2`, `crosses`, `dots`, `xlines`, `ylines`. 1x1 and 2x2 are rectangular grids of 1 and 2 meters side, respectively. | 79 | | **gridColor** | '#ccc' | Color of the grid. | 80 | 81 | The best way to work with them is to press `ctrl-alt-i` to open the [inspector](https://aframe.io/docs/master/introduction/visual-inspector-and-dev-tools.html#a-frame-inspector), search for 'environment' in the filter box and select it, and tweak the parameters while checking the changes in realtime. When you are happy, you can use the `Copy attributes` button or even better, copy the attributes logged in the browser's dev tools console. 82 | 83 | ## Performance 84 | 85 | The main idea of this component is to have a complete and visually interesting environment by just including one .js file, with no extra includes or requests. This requires to store all the assets inside the js or (in most of cases) to procedurally generate them. Despite of the computing time and increased file size, both options are normally faster than requesting and waiting for additional textures or model files. 86 | 87 | Apart from the parameter `dressingAmount`, there is not much difference among different values in parameters in terms of performance. Just keep `dressingAmount` value under watch and lower it if the performance is not optimal. 88 | 89 | ## Help and contact 90 | 91 | PRs are appreciated, issues are welcomed. For any question, ping @feiss at [aframevr in Slack](https://aframevr.slack.com/join/shared_invite/zt-f6rne3ly-ekVaBU~Xu~fsZHXr56jacQ) or [Discord](https://supermedium.com/discord). 92 | -------------------------------------------------------------------------------- /assets/aframeenvironment.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supermedium/aframe-environment-component/83f30045b5344dc4bb62c84aa11b52f886c24239/assets/aframeenvironment.gif -------------------------------------------------------------------------------- /assets/assets.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supermedium/aframe-environment-component/83f30045b5344dc4bb62c84aa11b52f886c24239/assets/assets.blend -------------------------------------------------------------------------------- /assets/how_to_add_new_dressing_geometry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supermedium/aframe-environment-component/83f30045b5344dc4bb62c84aa11b52f886c24239/assets/how_to_add_new_dressing_geometry.png -------------------------------------------------------------------------------- /dist/aframe-environment-component.min.js: -------------------------------------------------------------------------------- 1 | !function(e){function t(o){if(r[o])return r[o].exports;var i=r[o]={exports:{},id:o,loaded:!1};return e[o].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t){if("undefined"==typeof AFRAME)throw new Error("Component attempted to register before AFRAME was available.");AFRAME.registerComponent("environment",{schema:{active:{default:!1},preset:{default:"default",oneOf:["none","default","contact","egypt","checkerboard","forest","goaland","yavapai","goldmine","arches","threetowers","poison","tron","japan","dream","volcano","starry","osiris"]},seed:{type:"int",default:1,min:0,max:1e3},skyType:{default:"color",oneOf:["none","color","gradient","atmosphere"]},skyColor:{type:"color"},horizonColor:{type:"color"},lighting:{default:"distant",oneOf:["none","distant","point"]},shadow:{default:!1},shadowSize:{default:10},lightPosition:{type:"vec3",default:{x:0,y:1,z:-.2}},fog:{type:"float",default:0,min:0,max:1},flatShading:{default:!1},playArea:{type:"float",default:1,min:.5,max:10},stageSize:{type:"number",default:200,min:1,max:2e4},ground:{default:"hills",oneOf:["none","flat","hills","canyon","spikes","noise"]},groundYScale:{type:"float",default:3,min:0,max:50},groundTexture:{default:"none",oneOf:["none","checkerboard","squares","walkernoise"]},groundColor:{type:"color",default:"#553e35"},groundColor2:{type:"color",default:"#694439"},groundDensity:{type:"number",default:64,min:8,max:1024},groundFrequency:{type:"number",default:10,min:.1,max:1e3},dressing:{default:"none",oneOf:["none","cubes","pyramids","cylinders","hexagons","stones","trees","mushrooms","towers","apparatus","arches","torii"]},dressingAmount:{type:"int",default:10,min:0,max:1e3},dressingColor:{type:"color",default:"#795449"},dressingScale:{type:"float",default:5,min:0,max:100},dressingVariance:{type:"vec3",default:{x:1,y:1,z:1}},dressingUniformScale:{default:!0},dressingOnPlayArea:{type:"float",default:0,min:0,max:1},grid:{default:"none",oneOf:["none","1x1","2x2","crosses","dots","xlines","ylines"]},gridColor:{type:"color",default:"#ccc"}},multiple:!1,presets:{none:{},default:{active:!0,seed:1,skyType:"atmosphere",skyColor:"#88c",horizonColor:"#ddd",lighting:"distant",lightPosition:{x:-.11,y:1,z:.33},fog:.78,flatShading:!1,playArea:1,ground:"hills",groundYScale:3,groundTexture:"checkerboard",groundColor:"#454545",groundColor2:"#5d5d5d",dressing:"none",dressingAmount:10,dressingColor:"#795449",dressingScale:1,dressingVariance:{x:0,y:0,z:0},dressingUniformScale:!0,dressingOnPlayArea:0,grid:"none",gridColor:"#ccc",shadow:!1},contact:{active:!0,seed:14,skyType:"gradient",skyColor:"#478d54",horizonColor:"#b696cb",lighting:"distant",lightPosition:{x:0,y:2.01,z:-1},fog:.8,flatShading:!1,playArea:1,ground:"spikes",groundYScale:4.91,groundTexture:"none",groundColor:"#2e455f",groundColor2:"#694439",dressing:"apparatus",dressingAmount:7,dressingColor:"#657067",dressingScale:20,dressingVariance:{x:20,y:20,z:20},dressingUniformScale:!0,dressingOnPlayArea:0,grid:"1x1",gridColor:"#478d54",shadow:!1},egypt:{active:!0,seed:26,skyType:"gradient",skyColor:"#1b7660",horizonColor:"#e4b676",lighting:"distant",lightPosition:{x:0,y:1.65,z:-1},fog:.75,flatShading:!1,playArea:1,ground:"hills",groundYScale:5,groundTexture:"walkernoise",groundColor:"#664735",groundColor2:"#6c4b39",dressing:"pyramids",dressingAmount:10,dressingColor:"#7c5c45",dressingScale:5,dressingVariance:{x:20,y:20,z:20},dressingUniformScale:!0,dressingOnPlayArea:0,grid:"spots",gridColor:"#e4b676",shadow:!1},checkerboard:{active:!0,seed:1,skyType:"gradient",skyColor:"#0d0d0d",horizonColor:"#404040",lighting:"distant",lightPosition:{x:0,y:1,z:-.2},fog:.81,flatShading:!0,playArea:1,ground:"hills",groundYScale:4.81,groundTexture:"checkerboard",groundColor:"#252525",groundColor2:"#111111",dressing:"cubes",dressingAmount:10,dressingColor:"#9f9f9f",dressingScale:1.51,dressingVariance:{x:5,y:20,z:5},dressingUniformScale:!0,dressingOnPlayArea:0,grid:"dots",gridColor:"#ccc",shadow:!1},forest:{active:!0,seed:8,skyType:"gradient",skyColor:"#24b59f",horizonColor:"#eff9b7",lighting:"distant",lightPosition:{x:-1.2,y:.88,z:-.55},fog:.8,flatShading:!1,playArea:1,ground:"noise",groundYScale:4.18,groundTexture:"squares",groundColor:"#937a24",groundColor2:"#987d2e",dressing:"trees",dressingAmount:500,dressingColor:"#888b1d",dressingScale:1,dressingVariance:{x:10,y:10,z:10},dressingUniformScale:!0,dressingOnPlayArea:0,grid:"none",gridColor:"#c5a543",shadow:!1},goaland:{active:!0,seed:17,skyType:"gradient",skyColor:"#14645f",horizonColor:"#a3dab8",lighting:"point",lightPosition:{x:.1,y:4,z:.56},fog:.73,flatShading:!1,playArea:1,ground:"noise",groundYScale:.81,groundTexture:"none",groundColor:"#ae3241",groundColor2:"#db4453",dressing:"mushrooms",dressingAmount:150,dressingColor:"#a9313d",dressingScale:5,dressingVariance:{x:5,y:10,z:5},dressingUniformScale:!0,dressingOnPlayArea:0,grid:"dots",gridColor:"#239893",shadow:!1},yavapai:{active:!0,seed:11,skyType:"gradient",skyColor:"#239849",horizonColor:"#cfe0af",lighting:"distant",lightPosition:{x:.5,y:1,z:0},fog:.8,flatShading:!0,playArea:1,ground:"canyon",groundYScale:9.76,groundTexture:"walkernoise",groundColor:"#C66344",groundColor2:"#c96b4b",dressing:"stones",dressingAmount:500,dressingColor:"#C66344",dressingScale:.06,dressingVariance:{x:.2,y:.1,z:.2},dressingUniformScale:!0,dressingOnPlayArea:1,grid:"none",gridColor:"#239893",shadow:!1},goldmine:{active:!0,seed:53,skyType:"gradient",skyColor:"#1e1c1a",horizonColor:"#8c7964",lighting:"point",lightPosition:{x:-.09,y:3,z:.33},fog:.43,flatShading:!0,playArea:1.08,ground:"canyon",groundYScale:50,groundTexture:"none",groundColor:"#353535",groundColor2:"#454545",dressing:"hexagons",dressingAmount:300,dressingColor:"#fe921b",dressingScale:.5,dressingVariance:{x:2,y:8,z:2},dressingUniformScale:!0,dressingOnPlayArea:.03,grid:"none",gridColor:"#ccc",shadow:!1},threetowers:{active:!0,seed:5,skyType:"gradient",skyColor:"#23a06b",horizonColor:"#f5e170",lighting:"distant",lightPosition:{x:.5,y:1,z:0},fog:.8,flatShading:!1,playArea:1,ground:"spikes",groundYScale:4.26,groundTexture:"walkernoise",groundColor:"#273a49",groundColor2:"#2b464f",dressing:"towers",dressingAmount:3,dressingColor:"#5f6d94",dressingScale:50,dressingVariance:{x:10,y:100,z:10},dressingUniformScale:!0,dressingOnPlayArea:0,grid:"none",gridColor:"#239893",shadow:!1},poison:{active:!0,seed:92,skyType:"gradient",skyColor:"#1ea84a",horizonColor:"#177132",lighting:"distant",lightPosition:{x:.5,y:1,z:0},fog:.8,flatShading:!1,playArea:1,ground:"canyon",groundYScale:9.76,groundTexture:"none",groundColor:"#851f31",groundColor2:"#912235",dressing:"hexagons",dressingAmount:20,dressingColor:"#c7415b",dressingScale:20,dressingVariance:{x:20,y:200,z:20},dressingUniformScale:!1,dressingOnPlayArea:0,grid:"crosses",gridColor:"#1ea84a",shadow:!1},arches:{active:!0,seed:19,skyType:"atmosphere",skyColor:"#8cbdc8",horizonColor:"#ddd",lighting:"distant",lightPosition:{x:-.11,y:.16,z:.33},fog:.67,flatShading:!0,playArea:1,ground:"canyon",groundYScale:10,groundTexture:"walkernoise",groundColor:"#a87d6f",groundColor2:"#795449",dressing:"arches",dressingAmount:6,dressingColor:"#795449",dressingScale:26,dressingVariance:{x:20,y:40,z:20},dressingUniformScale:!0,dressingOnPlayArea:.04,grid:"none",gridColor:"#ccc",shadow:!1},tron:{active:!0,seed:14,skyType:"gradient",skyColor:"#091b39",horizonColor:"#284a9e",lighting:"distant",lightPosition:{x:-.72,y:.62,z:.4},fog:.8,flatShading:!1,playArea:1,ground:"spikes",groundYScale:4.91,groundTexture:"none",groundColor:"#061123",groundColor2:"#694439",dressing:"towers",dressingAmount:5,dressingColor:"#fb000e",dressingScale:15,dressingVariance:{x:20,y:20,z:20},dressingUniformScale:!0,dressingOnPlayArea:0,grid:"1x1",gridColor:"#fb000e",shadow:!1},japan:{active:!0,seed:14,skyType:"gradient",skyColor:"#7e5db5",horizonColor:"#b4adda",lighting:"distant",lightPosition:{x:1.33,y:1,z:.24},fog:.9,flatShading:!1,playArea:1,ground:"hills",groundYScale:25,groundTexture:"walkernoise",groundColor:"#7e5db5",groundColor2:"#cabdf5",dressing:"torii",dressingAmount:4,dressingColor:"#bc5e7c",dressingScale:15,dressingVariance:{x:0,y:0,z:0},dressingUniformScale:!0,dressingOnPlayArea:0,grid:"spots",gridColor:"#e4b676",shadow:!1},dream:{active:!0,seed:17,skyType:"gradient",skyColor:"#87faf4",horizonColor:"#b34093",lighting:"distant",lightPosition:{x:-.72,y:.53,z:.97},fog:.8,flatShading:!1,playArea:1,ground:"hills",groundYScale:20,groundTexture:"checkerboard",groundColor:"#b34093",groundColor2:"#c050a2",dressing:"mushrooms",dressingAmount:300,dressingColor:"#3cf7ed",dressingScale:.2,dressingVariance:{x:.2,y:.2,z:.2},dressingUniformScale:!0,dressingOnPlayArea:1,grid:"none",gridColor:"#239893",shadow:!1},volcano:{active:!0,seed:92,skyType:"gradient",skyColor:"#4a070f",horizonColor:"#f62300",lighting:"point",lightPosition:{x:.5,y:2.25,z:0},fog:.87,flatShading:!1,playArea:1,ground:"canyon",groundYScale:9.76,groundTexture:"walkernoise",groundColor:"#fb0803",groundColor2:"#510000",dressing:"arches",dressingAmount:15,dressingColor:"#fb0803",dressingScale:3,dressingVariance:{x:10,y:100,z:10},dressingUniformScale:!1,dressingOnPlayArea:.2,grid:"none",gridColor:"#fa0e00",shadow:!1},starry:{active:!0,seed:1,skyType:"atmosphere",skyColor:"#88c",horizonColor:"#ddd",lighting:"distant",lightPosition:{x:0,y:-.01,z:-.46},fog:.7,flatShading:!1,playArea:1,ground:"hills",groundYScale:3,groundTexture:"none",groundColor:"#553e35",groundColor2:"#694439",dressing:"none",dressingAmount:100,dressingColor:"#795449",dressingScale:5,dressingVariance:{x:1,y:1,z:1},dressingUniformScale:!0,grid:"1x1",dressingOnPlayArea:0,gridColor:"#39d2f2",shadow:!1},osiris:{active:!0,seed:46,skyType:"atmosphere",skyColor:"#88c",horizonColor:"#ddd",lighting:"distant",lightPosition:{x:0,y:.02,z:-.46},fog:0,flatShading:!1,playArea:1,ground:"hills",groundYScale:3,groundTexture:"none",groundColor:"#9e7b47",groundColor2:"#9e7b47",dressing:"pyramids",dressingAmount:7,dressingColor:"#9e7b47",dressingScale:5,dressingVariance:{x:30,y:30,z:30},dressingUniformScale:!0,grid:"dots",dressingOnPlayArea:0,gridColor:"#daa452",shadow:!1},moon:{active:!0,seed:11,skyType:"gradient",skyColor:"#000000",horizonColor:"#000000",lighting:"distant",lightPosition:{x:.5,y:1,z:0},fog:.8,flatShading:!0,playArea:1,ground:"canyon",groundYScale:9.76,groundTexture:"walkernoise",groundColor:"#D1D1D1",groundColor2:"#494949",dressing:"stones",dressingAmount:500,dressingColor:"#494949",dressingScale:.06,dressingVariance:{x:.2,y:.1,z:.2},dressingUniformScale:!0,dressingOnPlayArea:1,grid:"none",gridColor:"#239893",shadow:!1}},init:function(){this.environmentData={},this.rendererSystem=this.el.sceneEl.systems.renderer,this.STAGE_SIZE=this.data.stageSize,this.assets={arches:[{type:"mesh",vertices:[409,268,4,351,228,36,336,236,-57,-152,391,69,-135,358,88,-119,330,43,-20,358,-35,-153,357,-47,37,413,-26,-20,411,-14,-302,148,154,-339,121,-126,-389,200,-88,-477,193,-76,-314,346,-19,-314,306,-30,-250,296,-73,-267,237,-82,-212,303,-68,-245,200,-67,-223,304,108,-329,299,107,-289,350,76,-320,342,69,119,373,-39,38,370,8,113,367,52,492,202,-31,462,83,-104,447,71,-80,426,112,25,482,189,-7,222,372,6,121,402,41,87,382,67,221,346,55,559,93,-13,528,47,39,505,21,-111,528,54,-101,616,31,-53,442,256,-15,300,338,19,257,308,-79,408,256,-74,312,352,-26,384,297,-31,437,257,-47,-29,415,53,-232,377,59,-139,335,77,-132,344,2,-18,377,-37,-171,387,-28,-254,384,18,-651,-27,27,-435,-28,179,-345,149,165,-272,-28,23,-215,146,-2,-279,-29,-59,-211,145,-55,-337,-28,-128,-413,247,0,-293,363,24,-214,254,-36,-164,290,33,-284,150,94,-218,362,105,75,369,29,518,147,-63,447,190,-70,445,56,-105,391,185,-60,431,49,-33,459,83,26,470,162,42,130,390,53,167,341,-30,125,394,-45,239,368,-17,91,414,10,450,18,2,449,-27,-9,436,-28,-58,496,-27,-110,582,-28,-140,647,-27,-56,325,325,-45,-307,297,-56,-647,-28,-45,-188,310,-54,-264,197,113,-367,175,139,8,387,82,426,45,-55,114,359,-28,500,27,44,461,-29,13,-512,-27,-151,-152,376,-38,-490,-28,148,12,370,-28,442,160,42,465,194,32,381,183,-33,649,-27,-34,444,16,29,616,-28,25,417,267,-66,-132,352,-34,-322,-27,130,-271,86,-115,-635,-28,-121,-291,203,-99,176,405,-10,561,52,-93,371,305,9,311,237,-22,377,200,-81,-129,406,46,-154,371,99,-82,361,71,-21,354,26,-91,363,-27,-165,413,-12,-414,215,110,-238,127,26,-408,-28,-128,-674,-28,-94,-446,232,-39,-311,226,-90,-255,210,-61,-235,192,-11,-217,218,58,-269,299,124,-386,276,78,-399,281,42,15,373,58,16,393,75,549,107,-46,481,188,-68,409,120,-41,541,81,12,230,368,41,194,350,-50,224,361,-50,604,-28,-10,602,-27,35,486,56,-121,502,69,-120,457,-27,-110,226,317,-40,-584,-28,-124,439,-26,-30,467,-26,39,547,-27,-146,21,368,14,466,229,-29,578,-27,44,609,-27,-96,291,356,-15,290,306,34,255,321,28,231,311,-5,-251,386,50,-183,307,87,-152,307,24,-264,373,-12,-392,-27,190,-333,-28,84,-281,-27,54,-270,-28,-23,-308,-28,-101,-687,-27,-59,39,418,39,413,163,25,404,206,-90,54,400,-31,121,352,8,-454,41,148,-426,9,182,-564,115,3,-427,27,-107,-548,118,-32,-556,122,-53,-517,91,-101,-475,54,140,-461,52,-134,-558,119,-71,-434,286,59,-687,-31,52,-595,146,22,-670,-28,164,-537,166,122,-575,-28,217,-566,159,65,-470,152,136,-712,-29,102,-639,-29,211,-532,-30,181,-442,-30,-100],faces:[76,104,162,1,176,103,103,76,1,2,119,73,73,105,2,2,118,152,45,161,46,46,109,45,3,120,49,49,68,3,3,121,139,139,48,3,4,122,94,94,121,4,6,123,124,9,175,81,10,169,111,10,67,92,88,43,146,11,131,114,11,128,183,13,130,15,90,184,174,90,182,184,130,184,63,14,130,63,15,130,14,16,131,12,15,168,53,18,91,17,131,16,17,65,133,132,65,132,91,67,134,166,166,92,67,20,135,92,20,166,4,4,121,20,22,135,68,25,102,96,25,157,102,69,138,157,69,157,25,39,150,71,71,141,39,28,150,149,149,72,28,142,176,105,36,140,27,27,143,36,32,115,81,32,144,161,161,80,32,77,35,144,34,26,77,78,179,96,145,152,78,178,79,145,80,146,79,147,140,36,143,108,36,143,37,148,74,95,154,154,83,74,72,149,151,151,95,72,38,150,156,40,147,106,70,140,40,40,116,70,42,162,0,35,163,162,43,145,146,46,117,41,47,158,27,48,139,175,122,138,94,157,138,123,52,178,102,52,102,6,52,124,7,7,100,52,53,125,8,57,93,181,56,169,181,59,127,58,60,173,61,62,128,11,11,112,62,65,91,167,65,167,66,126,93,21,22,68,49,72,95,29,142,29,74,74,82,142,75,107,97,75,97,103,76,97,37,104,143,31,78,152,164,78,164,179,79,178,8,97,155,159,107,98,155,83,98,82,154,95,84,39,116,86,86,156,39,87,160,116,24,145,96,162,104,0,105,118,2,43,177,119,44,177,43,91,51,167,44,88,109,46,161,117,3,68,121,3,48,120,4,166,50,50,122,4,5,123,122,123,138,122,110,124,51,170,10,111,110,91,7,7,124,110,8,125,9,9,81,8,186,12,188,92,135,10,11,114,112,64,63,137,13,15,89,89,53,100,64,168,14,14,168,15,89,100,16,16,12,89,100,18,16,17,91,132,112,19,61,18,7,91,19,17,132,133,127,59,133,59,61,136,21,22,134,127,133,20,92,166,121,135,20,158,31,27,21,135,22,23,137,136,24,102,178,178,145,24,25,179,69,26,94,138,27,140,70,27,70,141,150,177,71,28,177,150,29,142,73,73,119,29,142,82,30,30,176,142,107,75,82,31,143,27,33,81,175,31,41,104,115,79,8,32,33,144,80,115,32,33,175,139,35,162,42,77,139,34,163,26,179,163,179,164,78,96,145,177,29,119,108,143,148,148,37,159,97,159,37,74,83,82,38,149,150,156,150,39,40,106,87,87,116,40,140,147,40,161,144,42,42,117,161,41,0,104,41,117,0,0,117,42,164,118,163,1,163,118,118,176,1,118,105,176,152,118,164,43,152,145,43,119,2,71,109,141,47,41,158,44,71,177,45,109,88,45,88,146,46,47,109,141,47,27,167,50,166,49,120,165,139,121,94,5,122,50,123,51,124,157,6,102,157,123,6,100,8,178,5,167,51,6,124,52,100,178,52,53,168,125,125,165,120,54,125,168,9,48,175,120,9,125,93,10,135,181,101,56,57,169,10,59,172,61,67,170,171,67,171,127,58,127,171,129,186,113,60,61,172,61,173,112,62,112,173,174,189,129,165,64,23,64,137,23,165,22,49,64,54,168,17,114,131,17,112,114,66,133,65,19,132,133,19,133,61,134,133,66,166,134,66,166,66,167,93,135,21,68,135,121,23,136,22,94,34,139,25,96,179,26,138,69,69,179,26,30,103,176,116,141,70,39,141,116,73,142,105,143,76,37,26,35,77,103,97,76,77,144,33,33,139,77,38,151,149,80,161,45,80,45,146,81,115,8,107,155,97,82,98,107,95,151,84,38,156,85,86,116,160,96,102,24,72,29,28,29,95,74,75,30,82,108,147,36,88,44,43,91,110,51,170,67,10,11,183,131,64,14,63,89,15,53,100,7,18,112,17,19,127,134,67,136,126,21,158,41,31,33,32,81,115,80,79,177,28,29,43,2,152,71,44,109,47,46,41,141,109,47,167,5,50,123,5,51,100,53,8,125,54,165,9,120,48,93,57,10,59,58,172,174,185,189,165,54,64,165,23,22,94,26,34,30,75,103,143,104,76,26,163,35,38,85,151,192,182,191,183,128,201,12,13,89,181,169,57,186,153,113,188,183,99,184,182,63,185,13,189,180,181,93,186,99,153,189,186,129,185,184,130,186,13,12,187,93,126,193,199,194,194,196,193,200,187,195,187,197,195,187,126,197,197,190,194,190,136,137,190,196,194,63,182,192,63,192,196,192,198,196,191,182,55,193,196,198,194,199,197,195,197,199,136,197,126,190,137,63,190,63,196,197,136,190,192,191,198,201,99,183,90,55,182,181,180,101,185,130,13,186,188,99,186,189,13,187,180,93,200,101,187,183,188,131,184,185,174,180,187,101,16,18,17,12,131,188,35,42,144,163,1,162,76,162,1,79,146,145]}],stones:[{type:"mesh",vertices:[-376,189,42,230,223,-310,353,162,-62,414,-23,-67,256,90,-475,24,85,-526,-418,-16,57,-432,66,-40,-199,151,-376,-155,49,467,-91,289,201,293,197,91,81,-17,-480,42,108,431,-359,-17,-250,383,-19,-243,194,-15,270,-272,180,293,-86,212,262,234,54,297,395,97,-302,-123,-21,-444,-416,-19,-123,-323,-18,267,-100,-16,429,-300,96,-361,163,-19,409,118,201,-431,-241,-18,391,-130,274,-309,306,-19,-399,-221,96,404],faces:[31,18,17,0,17,18,3,20,2,18,11,10,29,27,8,27,29,1,0,18,10,10,29,0,16,19,26,11,2,1,20,30,4,20,3,15,30,12,4,4,12,5,5,27,4,4,27,20,21,25,5,7,8,25,22,7,14,7,25,14,23,28,31,0,7,17,24,26,9,31,28,9,8,27,5,2,20,1,13,19,18,10,11,1,19,13,26,3,11,19,19,16,3,11,3,2,11,18,19,20,15,30,29,10,1,25,21,14,8,5,25,5,12,21,6,7,22,7,6,23,8,0,29,8,7,0,23,31,7,13,31,9,18,31,13,9,28,24,26,13,9,27,1,20,7,31,17]},{type:"mesh",vertices:[-217,34,-153,198,90,20,212,85,169,-131,93,171,197,113,30,173,121,164,315,29,-16,219,24,189,282,50,-102,232,38,-181,-195,-9,-166,-156,30,-207,-51,-9,-231,-180,91,-173,-19,73,-204,-280,23,96,-242,100,107,3,158,-82,109,88,221,275,-10,-40,236,-10,-135,-178,49,184,-1,-10,-243,265,-11,109,-12,-9,237,-36,46,251,-233,86,-81,93,77,-171,-163,133,69,18,16,263,296,44,93,131,-12,-226,-89,-10,-201,-273,-10,-51,-240,-9,110,190,-12,192,-253,-11,-92,42,43,-258,-115,-11,238,168,99,-88,-285,-10,24,71,124,-158,298,-10,10,116,150,-24,-282,44,39],faces:[44,16,26,13,26,16,0,26,13,27,14,41,4,5,1,7,30,2,28,5,43,41,39,27,17,43,41,43,4,39,13,28,17,17,41,13,28,43,17,24,29,38,29,35,7,18,25,29,5,18,2,18,5,3,30,42,6,30,35,23,19,20,8,8,20,9,9,39,8,1,30,8,31,37,9,11,14,37,14,27,37,32,11,12,11,37,12,11,0,13,33,40,44,44,26,33,33,0,36,34,38,15,44,40,15,21,3,16,27,39,9,2,30,1,21,25,3,16,3,28,28,3,5,4,43,5,41,43,39,13,16,28,25,21,38,38,29,25,7,18,29,29,24,35,18,7,2,18,3,25,30,23,42,30,7,35,8,30,6,6,19,8,6,42,19,8,39,1,37,31,22,27,9,37,9,20,31,10,11,32,11,10,0,12,37,22,14,13,41,14,11,13,33,26,0,36,0,10,21,44,15,16,44,21,15,40,34,38,21,15,4,1,39,5,2,1]},{type:"mesh",vertices:[-101,102,57,99,35,102,40,72,80,59,14,-168,-186,22,45,-176,25,-30,66,-7,146,153,-7,53,-110,47,-96,-90,-8,-146,150,-7,-12,-200,-7,8,-173,-7,-55,55,46,-60,125,-7,110,136,30,-10,-149,58,68,-15,82,-71,98,-7,-86,-34,-6,-194,-33,-7,171,-36,65,137,38,-8,-192,-103,-9,147,-12,62,-152],faces:[2,17,0,17,8,0,17,24,8,19,24,22,5,11,4,2,13,17,17,13,24,21,23,20,1,2,21,7,15,1,7,10,15,5,9,12,15,18,13,0,5,16,0,8,5,1,15,2,10,18,15,3,13,18,24,3,22,11,23,4,4,16,5,16,4,23,24,13,3,15,13,2,6,1,21,6,21,20,6,14,1,2,0,21,1,14,7,3,18,22,8,24,19,8,19,9,12,11,5,5,8,9,16,23,21,16,21,0]},{type:"mesh",vertices:[86,55,-18,58,38,73,97,-12,79,135,7,10,-93,-11,-72,-133,5,33,13,68,-32,94,-11,-57,-90,52,53,-24,-11,-106,-13,-10,104,-75,49,-69,-12,18,114,49,-12,-96,-46,-11,-85,-119,-11,-26,48,5,-111,-58,-11,105,-117,-12,52,-5,35,-93,123,-11,7],faces:[5,8,11,2,3,1,8,1,6,11,8,6,6,19,11,10,12,17,20,7,3,3,7,16,16,0,3,16,9,19,14,4,9,15,18,5,5,11,15,18,17,5,19,0,16,1,3,0,0,6,1,19,6,0,12,8,17,2,1,12,12,10,2,1,8,12,3,2,20,16,13,9,16,7,13,19,4,11,15,11,4,17,8,5,9,4,19]}],torii:[{type:"mesh",mirror:!0,flatShading:!0,vertices:[692,966,-52,661,834,-52,692,966,52,661,834,52,0,894,-52,0,776,-52,0,894,52,0,776,52,518,935,52,345,913,52,170,899,52,162,779,52,328,790,52,494,808,52,170,899,-52,345,913,-52,518,935,-52,494,808,-52,328,790,-52,162,779,-52,0,618,16,0,697,16,0,618,-16,0,697,-16,586,618,16,586,697,16,586,618,-16,586,697,-16,331,-29,-75,331,766,-52,369,-29,-65,357,766,-45,396,-29,-37,377,766,-26,406,-29,0,384,766,0,396,-29,37,377,766,26,369,-29,65,357,766,45,331,-29,75,331,766,52,294,-29,65,305,766,45,267,-29,37,286,766,26,257,-29,0,279,766,0,267,-29,-37,286,766,-26,294,-29,-65,305,766,-45,0,777,85,0,681,33,333,762,-75,333,806,-75,371,762,-65,371,806,-65,398,762,-37,398,806,-37,408,762,0,408,806,0,398,762,37,398,806,37,371,762,65,371,806,65,333,762,75,333,806,75,296,762,65,296,806,65,268,762,37,268,806,37,258,762,0,258,806,0,268,762,-37,268,806,-37,296,762,-65,296,806,-65,0,681,-33,0,777,-85,52,681,33,52,777,85,52,681,-33,52,777,-85],faces:[4,10,14,1,13,17,11,6,7,0,3,1,16,1,17,4,19,5,14,18,19,15,17,18,3,8,13,13,9,12,12,10,11,19,7,5,19,12,11,18,13,12,16,2,0,15,8,16,14,9,15,23,26,22,27,24,26,25,20,24,26,20,22,23,25,27,29,30,28,31,32,30,33,34,32,35,36,34,37,38,36,39,40,38,41,42,40,43,44,42,45,46,44,47,48,46,49,50,48,51,28,50,55,56,54,57,58,56,59,60,58,61,62,60,63,64,62,79,81,83,65,66,64,82,53,78,67,68,66,81,53,80,69,70,68,83,80,82,71,72,70,79,82,78,73,74,72,75,63,59,75,76,74,77,54,76,60,68,76,4,6,10,1,3,13,11,10,6,0,2,3,16,0,1,4,14,19,14,15,18,15,16,17,3,2,8,13,8,9,12,9,10,19,11,7,19,18,12,18,17,13,16,8,2,15,9,8,14,10,9,23,27,26,27,25,24,25,21,20,26,24,20,23,21,25,29,31,30,31,33,32,33,35,34,35,37,36,37,39,38,39,41,40,41,43,42,43,45,44,45,47,46,47,49,48,49,51,50,51,29,28,55,57,56,57,59,58,59,61,60,61,63,62,63,65,64,79,52,81,65,67,66,82,80,53,67,69,68,81,52,53,69,71,70,83,81,80,71,73,72,79,83,82,73,75,74,59,57,55,55,77,75,75,73,71,71,69,75,67,65,63,63,61,59,59,55,75,75,69,67,67,63,75,75,77,76,77,55,54,76,54,56,56,58,76,60,62,68,64,66,68,68,70,72,72,74,68,76,58,60,62,64,68,68,74,76]}],hexagons:[{type:"extrude",vertices:[-.198,-.302,.197,-.3,.372,0,.199,.298,-.202,.298,-.368,0]}],towers:[{type:"extrude",vertices:[-.054,-.178,-.007,-.182,.069,-.027,.189,.079,.178,.124,-.007,.097,-.145,.182,-.178,.144,-.079,-.021]},{type:"lathe",segments:4,vertices:[.004,.02,.012,.092,.042,.166,.067,.55,.101,.594,.105,.838,.193,.934,.18,.994]},{type:"lathe",segments:5,vertices:[.069,.216,.067,.562,.126,.562,.128,.774,.191,.774,.193,.986]}],trees:[{type:"lathe",noise:.015,segments:6,vertices:[1e-6,.826,.054,.832,.105,.854,.136,.9,.136,.958,.118,.994]},{type:"lathe",noise:.015,segments:14,vertices:[1e-6,.01,.069,.022,.13,.068,.178,.18,.189,.32,.191,.59,.193,.75,.138,.79,.018,.808,.018,.996]},{type:"lathe",noise:.015,segments:14,vertices:[1e-6,.436,.126,.46,.201,.57,.219,.72,.154,.846,.028,.884,.034,.996]}],apparatus:[{type:"lathe",segments:10,vertices:[1e-6,.23,.042,.23,.069,.36,.038,.362,.038,.372,.06,.372,.073,.572,.024,.572,.024,.67,.069,.67,.075,.722,.097,.724,.105,.852,.083,.902,.065,.902,.065,.924,.128,.924,.146,.996]},{type:"lathe",segments:16,vertices:[1e-6,.232,.229,.182,.486,.07,.356,.182,.213,.242,.154,.242,.144,.262,.178,.262,.126,.314,.04,.328,.038,.374,.058,.374,.071,.408,.026,.406,.03,.42,.091,.418,.034,.496,.01,.498,.03,.506,.014,.998]}],mushrooms:[{type:"lathe",noise:.02,segments:14,vertices:[1e-6,.006,.13,.018,.341,.084,.437,.144,.492,.234,.484,.246,.276,.232,.107,.284,.046,.346,.062,.852,.097,.956,.166,.998]},{type:"lathe",noise:.02,segments:10,vertices:[1e-6,.562,.091,.572,.172,.61,.223,.666,.256,.74,.258,.806,.246,.824,.062,.826,.065,.948,.097,.998]},{type:"lathe",noise:.02,segments:10,vertices:[1e-6,.768,.099,.772,.219,.802,.306,.844,.352,.886,.352,.908,.118,.904,.107,.93,.115,.966,.14,.996]}]};for(var e in this.assets)for(var t=0;to[n]){var s=(new THREE.Color).setStyle(i[n-1],THREE.NoColorSpace),a=(new THREE.Color).setStyle(i[n],THREE.NoColorSpace),l=(t-o[n])/(o[n-1]-o[n]);a.lerp(s,l),r=a;break}}return r.multiplyScalar(.9),r.lerp((new THREE.Color).setStyle(this.data.groundColor,THREE.NoColorSpace),.3),r.setRGB(r.r,r.g,r.b,THREE.SRGBColorSpace),"#"+r.getHexString()},update:function(e){var t;this.data.preset?(t=AFRAME.utils.clone(this.environmentData),this.environmentData={},Object.assign(this.environmentData,this.data),Object.assign(this.environmentData,this.presets[this.data.preset]),Object.assign(this.environmentData,this.el.components.environment.attrValue),console.log(this.environmentData)):(t=e,this.environmentData=this.data);var r=this.environmentData.skyType,o=new THREE.Vector3(this.environmentData.lightPosition.x,this.environmentData.lightPosition.y,this.environmentData.lightPosition.z);if(o.normalize(),this.sunlight){if(this.sunlight.setAttribute("position",this.environmentData.lightPosition),"atmosphere"!=r){var i=(new THREE.Color).setStyle(this.environmentData.skyColor,THREE.NoColorSpace);i.setRGB((i.r+1)/2,(i.g+1)/2,(i.b+1)/2,THREE.SRGBColorSpace),this.hemilight.setAttribute("light",{color:"#"+i.getHexString(),intensity:1.884}),this.sunlight.setAttribute("light",{intensity:1.884})}else this.hemilight.setAttribute("light",{color:"#CEE4F0",intensity:.314+1.57*o.y}),this.sunlight.setAttribute("light",{intensity:.314+1.57*o.y});this.sunlight.setAttribute("light",{castShadow:this.environmentData.shadow,shadowCameraLeft:-this.environmentData.shadowSize,shadowCameraBottom:-this.environmentData.shadowSize,shadowCameraRight:this.environmentData.shadowSize,shadowCameraTop:this.environmentData.shadowSize})}var n=this.environmentData.stageSize!==t.stageSize;if(n&&(this.STAGE_SIZE=this.data.stageSize,this.sky.setAttribute("radius",this.STAGE_SIZE)),r!==t.skyType||this.environmentData.skyColor!=t.skyColor||this.environmentData.horizonColor!=t.horizonColor){var s={};s.shader={none:"flat",color:"flat",gradient:"gradientshader",atmosphere:"skyshader"}[r],this.stars&&this.stars.setAttribute("visible","atmosphere"==r),"color"==r?(s.color=this.environmentData.skyColor,s.fog=!1):"gradient"==r&&(s.topColor=(new THREE.Color).setStyle(this.environmentData.skyColor,THREE.NoColorSpace),s.bottomColor=(new THREE.Color).setStyle(this.environmentData.horizonColor,THREE.NoColorSpace)),this.sky.setAttribute("material",s)}"atmosphere"==r&&(this.sky.setAttribute("material",{sunPosition:o}),this.setStars(2e3*(1-Math.max(0,8*(o.y+.08))))),this.environmentData.fog>0?this.el.sceneEl.setAttribute("fog",{color:this.getFogColor(r,o.y),far:(1.01-this.environmentData.fog)*this.STAGE_SIZE*2}):this.el.sceneEl.removeAttribute("fog"),this.sunlight.setAttribute("light",{type:"point"==this.environmentData.lighting?"point":"directional"}),this.sunlight.setAttribute("visible","none"!==this.environmentData.lighting),this.hemilight.setAttribute("visible","none"!==this.environmentData.lighting);var a=!this.groundGeometry||this.environmentData.seed!=t.seed||this.environmentData.ground!=t.ground||this.environmentData.playArea!=t.playArea||this.environmentData.flatShading!=t.flatShading||this.environmentData.groundDensity!=t.groundDensity||this.environmentData.groundFrequency!=t.groundFrequency||n;(a||this.environmentData.groundColor!=t.groundColor||this.environmentData.groundColor2!=t.groundColor2||this.environmentData.groundYScale!=t.groundYScale||this.environmentData.groundTexture!=t.groundTexture||this.environmentData.gridColor!=t.gridColor||this.environmentData.grid!=t.grid)&&(this.updateGround(a),this.hemilight&&this.hemilight.setAttribute("light",{groundColor:this.environmentData.groundColor})),(this.environmentData.seed!=t.seed||this.environmentData.dressingOnPlayArea!=t.dressingOnPlayArea||this.environmentData.dressing!=t.dressing||this.environmentData.flatShading!=t.flatShading||this.environmentData.dressingAmount!=t.dressingAmount||this.environmentData.dressingScale!=t.dressingScale||this.environmentData.dressingColor!=t.dressingColor||this.environmentData.dressingVariance.x!=t.dressingVariance.x||this.environmentData.dressingVariance.y!=t.dressingVariance.y||this.environmentData.dressingVariance.z!=t.dressingVariance.z||this.environmentData.dressingUniformScale!=t.dressingUniformScale||n)&&this.updateDressing(),this.sky.setAttribute("visible","none"!==r),this.el.setAttribute("visible",this.environmentData.active),this.environmentData.active||(this.userFog?this.el.sceneEl.setAttribute("fog",this.userFog):this.el.sceneEl.removeAttribute("fog")),this.dumpParametersDiff()},remove:function(){this.userFog?this.el.sceneEl.setAttribute("fog",this.userFog):this.el.sceneEl.removeAttribute("fog"),this.el.removeChild(this.hemilight),this.el.removeChild(this.sunlight),this.groundTexture&&this.groundTexture.dispose(),this.gridTexture&&this.gridTexture.dispose(),this.groundMaterial&&this.groundMaterial.dispose(),this.groundGeometry&&this.groundGeometry.dispose(),this.el.removeChild(this.ground);var e=this.dressing.getObject3D("mesh");e&&e.children.length>0&&(e.children[0].material.dispose(),e.children[0].geometry.dispose()),this.el.removeChild(this.dressing),this.el.removeChild(this.sky),this.removeStars()},logPreset:function(){var e="{";for(var t in this.schema)if("preset"!=t){e+=t+": ";var r=this.schema[t].type;e+="vec3"==r?"{ x: "+this.environmentData[t].x+", y: "+this.environmentData[t].y+", z: "+this.environmentData[t].z+"}":"string"==r||"color"==r?'"'+this.environmentData[t]+'"':this.environmentData[t],e+=", "}e+="}",console.log(e)},dumpParametersDiff:function(){function e(e){return Math.floor(1e3*e)/1e3}var t=[],r="none"!=this.data.preset&&this.presets[this.data.preset];r&&t.push("preset: "+this.data.preset);for(var o in this.schema)if(!("preset"==o||r&&void 0===r[o])){var i=r?r[o]:this.schema[o].default,n=this.environmentData[o],s=this.schema[o].type;if("vec3"==s){var a=i;"string"==typeof i&&(i=i.split(" "),a={x:i[0],y:i[1],z:i[2]}),e(a.x)==e(n.x)&&e(a.y)==e(n.y)&&e(a.z)==e(n.z)||t.push(o+": "+e(n.x)+" "+e(n.y)+" "+e(n.z))}else i!=n&&("number"==this.schema[o].type&&(n=e(n)),t.push(o+": "+n))}console.log("%c"+t.join("; "),"color: #f48;font-weight:bold")},random:function(e){return parseFloat("0."+Math.sin(9999*this.environmentData.seed*e).toString().substr(7))},updateGround:function(e){ 2 | var t=this.environmentData.groundDensity;if(e){var o="none"!=this.environmentData.ground;if(this.ground.setAttribute("visible",o),!o)return;this.groundGeometry||(this.groundGeometry=new THREE.PlaneGeometry(this.STAGE_SIZE+2,this.STAGE_SIZE+2,t-1,t-1));for(var i=new r(this.environmentData.seed),n=this.groundGeometry.attributes.position.array,s=n.length,a=this.environmentData.groundFrequency,l=a/t,d=0,h=0,g=2;gm?c:m,u<.01&&(u=0),n[g]=u,d+=l,d>=a&&(d=0,h+=l)}else n[g]=0;this.groundGeometry.computeVertexNormals(),this.groundGeometry.attributes.position.needsUpdate=!0,this.groundGeometry.attributes.normal.needsUpdate=!0}this.ground.setAttribute("scale",{z:this.environmentData.groundYScale});var p=2048,y=20,v=this.STAGE_SIZE/y;this.groundCanvas&&this.groundCanvas.width==p||(this.gridCanvas=document.createElement("canvas"),this.gridCanvas.width=p,this.gridCanvas.height=p,this.gridTexture=new THREE.Texture(this.gridCanvas),this.gridTexture.wrapS=THREE.RepeatWrapping,this.gridTexture.wrapT=THREE.RepeatWrapping,this.gridTexture.repeat.set(v,v),this.gridTexture.anisotropy=4,this.rendererSystem.applyColorCorrection(this.gridTexture),this.groundCanvas=document.createElement("canvas"),this.groundCanvas.width=p,this.groundCanvas.height=p,this.groundTexture=new THREE.Texture(this.groundCanvas),this.groundTexture.wrapS=THREE.RepeatWrapping,this.groundTexture.wrapT=THREE.RepeatWrapping,this.groundTexture.repeat.set(v,v),this.groundTexture.anisotropy=4,this.rendererSystem.applyColorCorrection(this.groundTexture),this.groundMaterialProps={map:this.groundTexture,emissive:new THREE.Color(16777215),emissiveMap:this.gridTexture},this.groundMaterialProps.flatShading=this.environmentData.flatShading,this.groundMaterial=new THREE.MeshLambertMaterial(this.groundMaterialProps));var C=this.groundCanvas.getContext("2d"),E=this.gridCanvas.getContext("2d");if(this.drawTexture(C,p,y),E.fillStyle="#000000",E.fillRect(0,0,p,p),this.drawGrid(E,p,y),this.groundTexture.needsUpdate=!0,this.gridTexture.needsUpdate=!0,e){var x=new THREE.Mesh(this.groundGeometry,this.groundMaterial);this.ground.setObject3D("mesh",x)}else this.ground.getObject3D("mesh").material=this.groundMaterial;this.ground.setAttribute("shadow",{cast:!1,receive:this.environmentData.shadow})},drawGrid:function(e,t,r){if("none"!=this.environmentData.grid){var o,i,n,s=Math.floor(r/2),a=t/(r/2);switch(e.fillStyle=this.environmentData.gridColor,this.environmentData.grid){case"1x1":case"2x2":for("1x1"==this.environmentData.grid&&(s*=2,a=t/r),o=0;o.5?s.clone():a.clone(),n.addScalar(.1*this.random(i+3)-.05),e.fillStyle="#"+n.getHexString(THREE.NoColorSpace),e.fillRect(i%m*f,Math.floor(i/m)*f,f,f);break;case"noise":d=e.getImageData(0,0,t,t),l=d.data,s=(new THREE.Color).setStyle(this.environmentData.groundColor,THREE.NoColorSpace),a=(new THREE.Color).setStyle(this.environmentData.groundColor2,THREE.NoColorSpace);var p=new THREE.Color(a.r-s.r,a.g-s.g,a.b-s.b),y=new r;for(i=0,c=0,h=l.length;i=C&&(A.x=A.x-C),A.y>=C&&(A.y=A.y-C),A.x<0&&(A.x=C+A.x),A.y<0&&(A.y=C+A.y)}x.putImageData(d,0,0),e.drawImage(E,0,0,t,t)}},getAssetGeometry:function(e){function t(e,t){for(var r=e.attributes.position.array,o=r.length,i=0;il&&(l=i[r+1]);o=new THREE.LatheGeometry(d,e[a].segments||8),o.applyMatrix4((new THREE.Matrix4).makeRotationFromEuler(new THREE.Euler(-Math.PI,0,0))),o.applyMatrix4((new THREE.Matrix4).makeTranslation(0,l,0)),o=o.toNonIndexed(),n.push(o)}else if("extrude"==e[a].type){var h=new THREE.Shape;for(i=e[a].vertices,r=0;r","#include ","uniform sampler2D skySampler;","uniform vec3 sunPosition;","varying vec3 vWorldPosition;","vec3 cameraPos = vec3(0., 0., 0.);","uniform float exposureBias;","uniform float turbidity;","uniform float reileigh;","uniform float mieCoefficient;","uniform float mieDirectionalG;","const float e = 2.71828182845904523536028747135266249775724709369995957;","const float pi = 3.141592653589793238462643383279502884197169;","const float n = 1.0003;","const float N = 2.545E25;","const float pn = 0.035;","const vec3 lambda = vec3(680E-9, 550E-9, 450E-9);","const vec3 K = vec3(0.686, 0.678, 0.666);","const float v = 4.0;","const float rayleighZenithLength = 8.4E3;","const float mieZenithLength = 1.25E3;","const vec3 up = vec3(0.0, 1.0, 0.0);","const float EE = 1000.0;","const float sunAngularDiameterCos = 0.999956676946448443553574619906976478926848692873900859324;","const float cutoffAngle = pi/1.95;","const float steepness = 1.5;","vec3 totalRayleigh(vec3 lambda)","{","return (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn));","}","vec3 simplifiedRayleigh()","{","return 0.0005 / vec3(94, 40, 18);","}","float rayleighPhase(float cosTheta)","{ ","return (3.0 / (16.0*pi)) * (1.0 + pow(cosTheta, 2.0));","}","vec3 totalMie(vec3 lambda, vec3 K, float T)","{","float c = (0.2 * T ) * 10E-18;","return 0.434 * c * pi * pow((2.0 * pi) / lambda, vec3(v - 2.0)) * K;","}","float hgPhase(float cosTheta, float g)","{","return (1.0 / (4.0*pi)) * ((1.0 - pow(g, 2.0)) / pow(1.0 - 2.0*g*cosTheta + pow(g, 2.0), 1.5));","}","float sunIntensity(float zenithAngleCos)","{","return EE * max(0.0, 1.0 - exp(-((cutoffAngle - acos(zenithAngleCos))/steepness)));","}","// Filmic ToneMapping http://filmicgames.com/archives/75","float A = 0.15;","float B = 0.50;","float C = 0.10;","float D = 0.20;","float E = 0.02;","float F = 0.30;","float W = 1000.0;","vec3 Uncharted2Tonemap(vec3 x)","{","return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;","}","void main() ","{","float sunfade = 1.0-clamp(1.0-exp((sunPosition.y/450000.0)),0.0,1.0);","float reileighCoefficient = reileigh - (1.0* (1.0-sunfade));","vec3 sunDirection = normalize(sunPosition);","float sunE = sunIntensity(dot(sunDirection, up));","vec3 betaR = simplifiedRayleigh() * reileighCoefficient;","vec3 betaM = totalMie(lambda, K, turbidity) * mieCoefficient;","float zenithAngle = acos(max(0.0, dot(up, normalize(vWorldPosition - cameraPos))));","float sR = rayleighZenithLength / (cos(zenithAngle) + 0.15 * pow(93.885 - ((zenithAngle * 180.0) / pi), -1.253));","float sM = mieZenithLength / (cos(zenithAngle) + 0.15 * pow(93.885 - ((zenithAngle * 180.0) / pi), -1.253));","vec3 Fex = exp(-(betaR * sR + betaM * sM));","float cosTheta = dot(normalize(vWorldPosition - cameraPos), sunDirection);","float rPhase = rayleighPhase(cosTheta*0.5+0.5);","vec3 betaRTheta = betaR * rPhase;","float mPhase = hgPhase(cosTheta, mieDirectionalG);","vec3 betaMTheta = betaM * mPhase;","vec3 Lin = pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * (1.0 - Fex),vec3(1.5));","Lin *= mix(vec3(1.0),pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * Fex,vec3(1.0/2.0)),clamp(pow(1.0-dot(up, sunDirection),5.0),0.0,1.0));","vec3 direction = normalize(vWorldPosition - cameraPos);","float theta = acos(direction.y); // elevation --> y-axis, [-pi/2, pi/2]","float phi = atan(direction.z, direction.x); // azimuth --> x-axis [-pi/2, pi/2]","vec2 uv = vec2(phi, theta) / vec2(2.0*pi, pi) + vec2(0.5, 0.0);","vec3 L0 = vec3(0.1) * Fex;","float sundisk = smoothstep(sunAngularDiameterCos,sunAngularDiameterCos+0.00002,cosTheta);","L0 += (sunE * 19000.0 * Fex)*sundisk;","vec3 whiteScale = 1.0/Uncharted2Tonemap(vec3(W));","vec3 texColor = (Lin+L0);","texColor *= 0.04;","texColor += vec3(0.0,0.001,0.0025)*0.3;","vec3 curr = Uncharted2Tonemap(exposureBias*texColor);","vec3 color = curr*whiteScale;","vec3 retColor = pow(color,vec3(1.0/(1.2+(1.2*sunfade))));","gl_FragColor.rgb = retColor;","gl_FragColor.a = 1.0;","#include ","}"].join("\n")}),AFRAME.registerShader("gradientshader",{schema:{topColor:{type:"color",default:"1 0 0",is:"uniform"},bottomColor:{type:"color",default:"0 0 1",is:"uniform"}},vertexShader:["varying vec3 vWorldPosition;","void main() {"," vec4 worldPosition = modelMatrix * vec4( position, 1.0 );"," vWorldPosition = worldPosition.xyz;"," gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );","}"].join("\n"),fragmentShader:["#include ","#include ","uniform vec3 bottomColor;","uniform vec3 topColor;","uniform float offset;","varying vec3 vWorldPosition;","void main() {"," float h = normalize( vWorldPosition ).y;"," gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max(h, 0.0 ), 0.8 ), 0.0 ) ), 1.0 );"," #include ","}"].join("\n")});var r=function(e){var t;this.grad3=[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]],this.p=[];var r;for(r=0;r<256;r++)t=parseFloat("0."+Math.sin(9999*e*r).toString().substr(7)),this.p[r]=Math.floor(256*t);for(this.perm=[],r=0;r<512;r++)this.perm[r]=this.p[255&r]};r.prototype.dot=function(e,t,r,o){return e[0]*t+e[1]*r+e[2]*o},r.prototype.mix=function(e,t,r){return(1-r)*e+r*t},r.prototype.fade=function(e){return e*e*e*(e*(6*e-15)+10)},r.prototype.noise=function(e,t,r){var o=Math.floor(e),i=Math.floor(t),n=Math.floor(r);e-=o,t-=i,r-=n,o&=255,i&=255,n&=255;var s=this.perm[o+this.perm[i+this.perm[n]]]%12,a=this.perm[o+this.perm[i+this.perm[n+1]]]%12,l=this.perm[o+this.perm[i+1+this.perm[n]]]%12,d=this.perm[o+this.perm[i+1+this.perm[n+1]]]%12,h=this.perm[o+1+this.perm[i+this.perm[n]]]%12,g=this.perm[o+1+this.perm[i+this.perm[n+1]]]%12,u=this.perm[o+1+this.perm[i+1+this.perm[n]]]%12,c=this.perm[o+1+this.perm[i+1+this.perm[n+1]]]%12,m=this.dot(this.grad3[s],e,t,r),f=this.dot(this.grad3[h],e-1,t,r),p=this.dot(this.grad3[l],e,t-1,r),y=this.dot(this.grad3[u],e-1,t-1,r),v=this.dot(this.grad3[a],e,t,r-1),C=this.dot(this.grad3[g],e-1,t,r-1),E=this.dot(this.grad3[d],e,t-1,r-1),x=this.dot(this.grad3[c],e-1,t-1,r-1),S=this.fade(e),T=this.fade(t),b=this.fade(r),w=this.mix(m,f,S),A=this.mix(v,C,S),D=this.mix(p,y,S),R=this.mix(E,x,S),M=this.mix(w,D,T),z=this.mix(A,R,T),k=this.mix(M,z,b);return k}}]); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A-Frame Environment Component 6 | 7 | 8 | 9 | 10 | 11 | 12 | 85 | 86 | 87 |
88 | 89 | aframe-environment-component 90 |

A component for adding procedural environments to your A-Frame demos and experiences.

91 |

92 | Press ctrl + alt + i to enter inspector and tweak parameters.

93 |

94 | 95 | GitHub / How to use it 96 |

97 |
98 |

99 | 100 | forest 101 | 102 |

103 | 104 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* global AFRAME, THREE */ 2 | 3 | if (typeof AFRAME === 'undefined') { 4 | throw new Error('Component attempted to register before AFRAME was available.'); 5 | } 6 | 7 | AFRAME.registerComponent('environment', { 8 | schema: { 9 | active: {default: false}, 10 | preset: {default: 'default', oneOf: ['none', 'default', 'contact', 'egypt', 'checkerboard', 'forest', 'goaland', 'yavapai', 'goldmine', 'arches', 'threetowers', 'poison', 'tron', 'japan', 'dream', 'volcano', 'starry', 'osiris']}, 11 | seed: {type: 'int', default: 1, min: 0, max: 1000}, 12 | 13 | skyType: {default: 'color', oneOf:['none', 'color', 'gradient', 'atmosphere']}, 14 | skyColor: {type: 'color'}, 15 | horizonColor: {type: 'color'}, 16 | lighting: {default: 'distant', oneOf: ['none', 'distant', 'point']}, 17 | shadow: {default: false}, 18 | shadowSize: { default: 10}, 19 | lightPosition: {type:'vec3', default: {x: 0, y: 1, z: -0.2}}, 20 | fog: {type:'float', default: 0, min: 0, max: 1}, 21 | 22 | flatShading: {default: false}, 23 | playArea: {type: 'float', default: 1, min: 0.5, max: 10}, 24 | stageSize: {type: 'number', default: 200, min: 1, max: 20000}, 25 | 26 | ground: {default: 'hills', oneOf:['none', 'flat', 'hills', 'canyon', 'spikes', 'noise']}, 27 | groundYScale: {type: 'float', default: 3, min: 0, max: 50}, 28 | groundTexture: {default: 'none', oneOf:['none', 'checkerboard', 'squares', 'walkernoise']}, 29 | groundColor: {type: 'color', default: '#553e35'}, 30 | groundColor2: {type: 'color', default: '#694439'}, 31 | groundDensity: {type: 'number', default: 64, min: 8, max: 1024}, 32 | groundFrequency: {type: 'number', default: 10, min: 0.1, max: 1000}, 33 | 34 | dressing: {default: 'none', oneOf:['none', 'cubes', 'pyramids', 'cylinders', 'hexagons', 'stones', 'trees', 'mushrooms', 'towers', 'apparatus', 'arches', 'torii']}, 35 | dressingAmount: {type: 'int', default: 10, min: 0, max: 1000}, 36 | dressingColor: {type: 'color', default: '#795449'}, 37 | dressingScale: {type: 'float', default: 5, min: 0, max: 100}, 38 | dressingVariance: {type: 'vec3', default: {x: 1, y: 1, z: 1}}, 39 | dressingUniformScale: {default: true}, 40 | dressingOnPlayArea: {type: 'float', default: 0, min: 0, max: 1}, 41 | 42 | grid: {default:'none', oneOf:['none', '1x1', '2x2', 'crosses', 'dots', 'xlines', 'ylines']}, 43 | gridColor: {type: 'color', default: '#ccc'} 44 | }, 45 | 46 | multiple: false, 47 | 48 | presets: { 49 | 'none' : {}, 50 | 'default' : {active: true, seed: 1, skyType: 'atmosphere', skyColor: '#88c', horizonColor: '#ddd', lighting: 'distant', lightPosition: { x: -0.11, y: 1, z: 0.33}, fog: 0.78, flatShading: false, playArea: 1, ground: 'hills', groundYScale: 3, groundTexture: 'checkerboard', groundColor: '#454545', groundColor2: '#5d5d5d', dressing: 'none', dressingAmount: 10, dressingColor: '#795449', dressingScale: 1, dressingVariance: { x: 0, y: 0, z: 0}, dressingUniformScale: true, dressingOnPlayArea: 0, grid: 'none', gridColor: '#ccc', shadow: false}, 51 | 'contact': {active: true, seed: 14, skyType: 'gradient', skyColor: '#478d54', horizonColor: '#b696cb', lighting: 'distant', lightPosition: { x: 0, y: 2.01, z: -1}, fog: 0.8, flatShading: false, playArea: 1, ground: 'spikes', groundYScale: 4.91, groundTexture: 'none', groundColor: '#2e455f', groundColor2: '#694439', dressing: 'apparatus', dressingAmount: 7, dressingColor: '#657067', dressingScale: 20, dressingVariance: { x: 20, y: 20, z: 20}, dressingUniformScale: true, dressingOnPlayArea: 0, grid: '1x1', gridColor: '#478d54', shadow: false}, 52 | 'egypt': {active: true, seed: 26, skyType: 'gradient', skyColor: '#1b7660', horizonColor: '#e4b676', lighting: 'distant', lightPosition: { x: 0, y: 1.65, z: -1}, fog: 0.75, flatShading: false, playArea: 1, ground: 'hills', groundYScale: 5, groundTexture: 'walkernoise', groundColor: '#664735', groundColor2: '#6c4b39', dressing: 'pyramids', dressingAmount: 10, dressingColor: '#7c5c45', dressingScale: 5, dressingVariance: { x: 20, y: 20, z: 20}, dressingUniformScale: true, dressingOnPlayArea: 0, grid: 'spots', gridColor: '#e4b676', shadow: false}, 53 | 'checkerboard': {active: true, seed: 1, skyType: 'gradient', skyColor: '#0d0d0d', horizonColor: '#404040', lighting: 'distant', lightPosition: { x: 0, y: 1, z: -0.2}, fog: 0.81, flatShading: true, playArea: 1, ground: 'hills', groundYScale: 4.81, groundTexture: 'checkerboard', groundColor: '#252525', groundColor2: '#111111', dressing: 'cubes', dressingAmount: 10, dressingColor: '#9f9f9f', dressingScale: 1.51, dressingVariance: { x: 5, y: 20, z: 5}, dressingUniformScale: true, dressingOnPlayArea: 0, grid: 'dots', gridColor: '#ccc', shadow: false}, 54 | 'forest': {active: true, seed: 8, skyType: 'gradient', skyColor: '#24b59f', horizonColor: '#eff9b7', lighting: 'distant', lightPosition: { x: -1.2, y: 0.88, z: -0.55}, fog: 0.8, flatShading: false, playArea: 1, ground: 'noise', groundYScale: 4.18, groundTexture: 'squares', groundColor: '#937a24', groundColor2: '#987d2e', dressing: 'trees', dressingAmount: 500, dressingColor: '#888b1d', dressingScale: 1, dressingVariance: { x: 10, y: 10, z: 10}, dressingUniformScale: true, dressingOnPlayArea: 0, grid: 'none', gridColor: '#c5a543', shadow: false}, 55 | 'goaland': {active: true, seed: 17, skyType: 'gradient', skyColor: '#14645f', horizonColor: '#a3dab8', lighting: 'point', lightPosition: { x: 0.1, y: 4, z: 0.56}, fog: 0.73, flatShading: false, playArea: 1, ground: 'noise', groundYScale: 0.81, groundTexture: 'none', groundColor: '#ae3241', groundColor2: '#db4453', dressing: 'mushrooms', dressingAmount: 150, dressingColor: '#a9313d', dressingScale: 5, dressingVariance: { x: 5, y: 10, z: 5}, dressingUniformScale: true, dressingOnPlayArea: 0, grid: 'dots', gridColor: '#239893', shadow: false}, 56 | 'yavapai': {active: true, seed: 11, skyType: 'gradient', skyColor: '#239849', horizonColor: '#cfe0af', lighting: 'distant', lightPosition: { x: 0.5, y: 1, z: 0}, fog: 0.8, flatShading: true, playArea: 1, ground: 'canyon', groundYScale: 9.76, groundTexture: 'walkernoise', groundColor: '#C66344', groundColor2: '#c96b4b', dressing: 'stones', dressingAmount: 500, dressingColor: '#C66344', dressingScale: 0.06, dressingVariance: { x: 0.2, y: 0.1, z: 0.2}, dressingUniformScale: true, dressingOnPlayArea: 1, grid: 'none', gridColor: '#239893', shadow: false}, 57 | 'goldmine': {active: true, seed: 53, skyType: 'gradient', skyColor: '#1e1c1a', horizonColor: '#8c7964', lighting: 'point', lightPosition: { x: -0.09, y: 3, z: 0.33}, fog: 0.43, flatShading: true, playArea: 1.08, ground: 'canyon', groundYScale: 50, groundTexture: 'none', groundColor: '#353535', groundColor2: '#454545', dressing: 'hexagons', dressingAmount: 300, dressingColor: '#fe921b', dressingScale: 0.5, dressingVariance: { x: 2, y: 8, z: 2}, dressingUniformScale: true, dressingOnPlayArea: 0.03, grid: 'none', gridColor: '#ccc', shadow: false}, 58 | 'threetowers': {active: true, seed: 5, skyType: 'gradient', skyColor: '#23a06b', horizonColor: '#f5e170', lighting: 'distant', lightPosition: { x: 0.5, y: 1, z: 0}, fog: 0.8, flatShading: false, playArea: 1, ground: 'spikes', groundYScale: 4.26, groundTexture: 'walkernoise', groundColor: '#273a49', groundColor2: '#2b464f', dressing: 'towers', dressingAmount: 3, dressingColor: '#5f6d94', dressingScale: 50, dressingVariance: { x: 10, y: 100, z: 10}, dressingUniformScale: true, dressingOnPlayArea: 0, grid: 'none', gridColor: '#239893', shadow: false}, 59 | 'poison': {active: true, seed: 92, skyType: 'gradient', skyColor: '#1ea84a', horizonColor: '#177132', lighting: 'distant', lightPosition: { x: 0.5, y: 1, z: 0}, fog: 0.8, flatShading: false, playArea: 1, ground: 'canyon', groundYScale: 9.76, groundTexture: 'none', groundColor: '#851f31', groundColor2: '#912235', dressing: 'hexagons', dressingAmount: 20, dressingColor: '#c7415b', dressingScale: 20, dressingVariance: { x: 20, y: 200, z: 20}, dressingUniformScale: false, dressingOnPlayArea: 0, grid: 'crosses', gridColor: '#1ea84a', shadow: false}, 60 | 'arches': {active: true, seed: 19, skyType: 'atmosphere', skyColor: '#8cbdc8', horizonColor: '#ddd', lighting: 'distant', lightPosition: { x: -0.11, y: 0.16, z: 0.33}, fog: 0.67, flatShading: true, playArea: 1, ground: 'canyon', groundYScale: 10, groundTexture: 'walkernoise', groundColor: '#a87d6f', groundColor2: '#795449', dressing: 'arches', dressingAmount: 6, dressingColor: '#795449', dressingScale: 26, dressingVariance: { x: 20, y: 40, z: 20}, dressingUniformScale: true, dressingOnPlayArea: 0.04, grid: 'none', gridColor: '#ccc', shadow: false}, 61 | 'tron': {active: true, seed: 14, skyType: 'gradient', skyColor: '#091b39', horizonColor: '#284a9e', lighting: 'distant', lightPosition: { x: -0.72, y: 0.62, z: 0.4}, fog: 0.8, flatShading: false, playArea: 1, ground: 'spikes', groundYScale: 4.91, groundTexture: 'none', groundColor: '#061123', groundColor2: '#694439', dressing: 'towers', dressingAmount: 5, dressingColor: '#fb000e', dressingScale: 15, dressingVariance: { x: 20, y: 20, z: 20}, dressingUniformScale: true, dressingOnPlayArea: 0, grid: '1x1', gridColor: '#fb000e', shadow: false}, 62 | 'japan': {active: true, seed: 14, skyType: 'gradient', skyColor: '#7e5db5', horizonColor: '#b4adda', lighting: 'distant', lightPosition: { x: 1.33, y: 1, z: 0.24}, fog: 0.9, flatShading: false, playArea: 1, ground: 'hills', groundYScale: 25, groundTexture: 'walkernoise', groundColor: '#7e5db5', groundColor2: '#cabdf5', dressing: 'torii', dressingAmount: 4, dressingColor: '#bc5e7c', dressingScale: 15, dressingVariance: { x: 0, y: 0, z: 0}, dressingUniformScale: true, dressingOnPlayArea: 0, grid: 'spots', gridColor: '#e4b676', shadow: false}, 63 | 'dream': {active: true, seed: 17, skyType: 'gradient', skyColor: '#87faf4', horizonColor: '#b34093', lighting: 'distant', lightPosition: { x: -0.72, y: 0.53, z: 0.97}, fog: 0.8, flatShading: false, playArea: 1, ground: 'hills', groundYScale: 20, groundTexture: 'checkerboard', groundColor: '#b34093', groundColor2: '#c050a2', dressing: 'mushrooms', dressingAmount: 300, dressingColor: '#3cf7ed', dressingScale: 0.2, dressingVariance: { x: 0.2, y: 0.2, z: 0.2}, dressingUniformScale: true, dressingOnPlayArea: 1, grid: 'none', gridColor: '#239893', shadow: false}, 64 | 'volcano': {active: true, seed: 92, skyType: 'gradient', skyColor: '#4a070f', horizonColor: '#f62300', lighting: 'point', lightPosition: { x: 0.5, y: 2.25, z: 0}, fog: 0.87, flatShading: false, playArea: 1, ground: 'canyon', groundYScale: 9.76, groundTexture: 'walkernoise', groundColor: '#fb0803', groundColor2: '#510000', dressing: 'arches', dressingAmount: 15, dressingColor: '#fb0803', dressingScale: 3, dressingVariance: { x: 10, y: 100, z: 10}, dressingUniformScale: false, dressingOnPlayArea: 0.2, grid: 'none', gridColor: '#fa0e00', shadow: false}, 65 | 'starry': {active: true, seed: 1, skyType: 'atmosphere', skyColor: '#88c', horizonColor: '#ddd', lighting: 'distant', lightPosition: { x: 0, y: -0.01, z: -0.46}, fog: 0.7, flatShading: false, playArea: 1, ground: 'hills', groundYScale: 3, groundTexture: 'none', groundColor: '#553e35', groundColor2: '#694439', dressing: 'none', dressingAmount: 100, dressingColor: '#795449', dressingScale: 5, dressingVariance: { x: 1, y: 1, z: 1}, dressingUniformScale: true, grid: '1x1', dressingOnPlayArea: 0, gridColor: '#39d2f2', shadow: false}, 66 | 'osiris': {active: true, seed: 46, skyType: 'atmosphere', skyColor: '#88c', horizonColor: '#ddd', lighting: 'distant', lightPosition: { x: 0, y: 0.02, z: -0.46}, fog: 0, flatShading: false, playArea: 1, ground: 'hills', groundYScale: 3, groundTexture: 'none', groundColor: '#9e7b47', groundColor2: '#9e7b47', dressing: 'pyramids', dressingAmount: 7, dressingColor: '#9e7b47', dressingScale: 5, dressingVariance: { x: 30, y: 30, z: 30}, dressingUniformScale: true, grid: 'dots', dressingOnPlayArea: 0, gridColor: '#daa452', shadow: false}, 67 | 'moon': {active: true, seed: 11, skyType: 'gradient', skyColor: '#000000', horizonColor: '#000000', lighting: 'distant', lightPosition: { x: 0.5, y: 1, z: 0}, fog: 0.8, flatShading: true, playArea: 1, ground: 'canyon', groundYScale: 9.76, groundTexture: 'walkernoise', groundColor: '#D1D1D1', groundColor2: '#494949', dressing: 'stones', dressingAmount: 500, dressingColor: '#494949', dressingScale: 0.06, dressingVariance: { x: 0.2, y: 0.1, z: 0.2}, dressingUniformScale: true, dressingOnPlayArea: 1, grid: 'none', gridColor: '#239893', shadow: false} 68 | }, 69 | 70 | init: function () { 71 | this.environmentData = {}; 72 | 73 | // renderer system for color correction 74 | this.rendererSystem = this.el.sceneEl.systems.renderer; 75 | 76 | // stage ground diameter (and sky radius) 77 | this.STAGE_SIZE = this.data.stageSize; 78 | 79 | // data for dressing meshes 80 | this.assets = { 81 | 'arches': [ 82 | { 83 | type: 'mesh', 84 | vertices: [409,268,4,351,228,36,336,236,-57,-152,391,69,-135,358,88,-119,330,43,-20,358,-35,-153,357,-47,37,413,-26,-20,411,-14,-302,148,154,-339,121,-126,-389,200,-88,-477,193,-76,-314,346,-19,-314,306,-30,-250,296,-73,-267,237,-82,-212,303,-68,-245,200,-67,-223,304,108,-329,299,107,-289,350,76,-320,342,69,119,373,-39,38,370,8,113,367,52,492,202,-31,462,83,-104,447,71,-80,426,112,25,482,189,-7,222,372,6,121,402,41,87,382,67,221,346,55,559,93,-13,528,47,39,505,21,-111,528,54,-101,616,31,-53,442,256,-15,300,338,19,257,308,-79,408,256,-74,312,352,-26,384,297,-31,437,257,-47,-29,415,53,-232,377,59,-139,335,77,-132,344,2,-18,377,-37,-171,387,-28,-254,384,18,-651,-27,27,-435,-28,179,-345,149,165,-272,-28,23,-215,146,-2,-279,-29,-59,-211,145,-55,-337,-28,-128,-413,247,0,-293,363,24,-214,254,-36,-164,290,33,-284,150,94,-218,362,105,75,369,29,518,147,-63,447,190,-70,445,56,-105,391,185,-60,431,49,-33,459,83,26,470,162,42,130,390,53,167,341,-30,125,394,-45,239,368,-17,91,414,10,450,18,2,449,-27,-9,436,-28,-58,496,-27,-110,582,-28,-140,647,-27,-56,325,325,-45,-307,297,-56,-647,-28,-45,-188,310,-54,-264,197,113,-367,175,139,8,387,82,426,45,-55,114,359,-28,500,27,44,461,-29,13,-512,-27,-151,-152,376,-38,-490,-28,148,12,370,-28,442,160,42,465,194,32,381,183,-33,649,-27,-34,444,16,29,616,-28,25,417,267,-66,-132,352,-34,-322,-27,130,-271,86,-115,-635,-28,-121,-291,203,-99,176,405,-10,561,52,-93,371,305,9,311,237,-22,377,200,-81,-129,406,46,-154,371,99,-82,361,71,-21,354,26,-91,363,-27,-165,413,-12,-414,215,110,-238,127,26,-408,-28,-128,-674,-28,-94,-446,232,-39,-311,226,-90,-255,210,-61,-235,192,-11,-217,218,58,-269,299,124,-386,276,78,-399,281,42,15,373,58,16,393,75,549,107,-46,481,188,-68,409,120,-41,541,81,12,230,368,41,194,350,-50,224,361,-50,604,-28,-10,602,-27,35,486,56,-121,502,69,-120,457,-27,-110,226,317,-40,-584,-28,-124,439,-26,-30,467,-26,39,547,-27,-146,21,368,14,466,229,-29,578,-27,44,609,-27,-96,291,356,-15,290,306,34,255,321,28,231,311,-5,-251,386,50,-183,307,87,-152,307,24,-264,373,-12,-392,-27,190,-333,-28,84,-281,-27,54,-270,-28,-23,-308,-28,-101,-687,-27,-59,39,418,39,413,163,25,404,206,-90,54,400,-31,121,352,8,-454,41,148,-426,9,182,-564,115,3,-427,27,-107,-548,118,-32,-556,122,-53,-517,91,-101,-475,54,140,-461,52,-134,-558,119,-71,-434,286,59,-687,-31,52,-595,146,22,-670,-28,164,-537,166,122,-575,-28,217,-566,159,65,-470,152,136,-712,-29,102,-639,-29,211,-532,-30,181,-442,-30,-100], 85 | faces: [76,104,162,1,176,103,103,76,1,2,119,73,73,105,2,2,118,152,45,161,46,46,109,45,3,120,49,49,68,3,3,121,139,139,48,3,4,122,94,94,121,4,6,123,124,9,175,81,10,169,111,10,67,92,88,43,146,11,131,114,11,128,183,13,130,15,90,184,174,90,182,184,130,184,63,14,130,63,15,130,14,16,131,12,15,168,53,18,91,17,131,16,17,65,133,132,65,132,91,67,134,166,166,92,67,20,135,92,20,166,4,4,121,20,22,135,68,25,102,96,25,157,102,69,138,157,69,157,25,39,150,71,71,141,39,28,150,149,149,72,28,142,176,105,36,140,27,27,143,36,32,115,81,32,144,161,161,80,32,77,35,144,34,26,77,78,179,96,145,152,78,178,79,145,80,146,79,147,140,36,143,108,36,143,37,148,74,95,154,154,83,74,72,149,151,151,95,72,38,150,156,40,147,106,70,140,40,40,116,70,42,162,0,35,163,162,43,145,146,46,117,41,47,158,27,48,139,175,122,138,94,157,138,123,52,178,102,52,102,6,52,124,7,7,100,52,53,125,8,57,93,181,56,169,181,59,127,58,60,173,61,62,128,11,11,112,62,65,91,167,65,167,66,126,93,21,22,68,49,72,95,29,142,29,74,74,82,142,75,107,97,75,97,103,76,97,37,104,143,31,78,152,164,78,164,179,79,178,8,97,155,159,107,98,155,83,98,82,154,95,84,39,116,86,86,156,39,87,160,116,24,145,96,162,104,0,105,118,2,43,177,119,44,177,43,91,51,167,44,88,109,46,161,117,3,68,121,3,48,120,4,166,50,50,122,4,5,123,122,123,138,122,110,124,51,170,10,111,110,91,7,7,124,110,8,125,9,9,81,8,186,12,188,92,135,10,11,114,112,64,63,137,13,15,89,89,53,100,64,168,14,14,168,15,89,100,16,16,12,89,100,18,16,17,91,132,112,19,61,18,7,91,19,17,132,133,127,59,133,59,61,136,21,22,134,127,133,20,92,166,121,135,20,158,31,27,21,135,22,23,137,136,24,102,178,178,145,24,25,179,69,26,94,138,27,140,70,27,70,141,150,177,71,28,177,150,29,142,73,73,119,29,142,82,30,30,176,142,107,75,82,31,143,27,33,81,175,31,41,104,115,79,8,32,33,144,80,115,32,33,175,139,35,162,42,77,139,34,163,26,179,163,179,164,78,96,145,177,29,119,108,143,148,148,37,159,97,159,37,74,83,82,38,149,150,156,150,39,40,106,87,87,116,40,140,147,40,161,144,42,42,117,161,41,0,104,41,117,0,0,117,42,164,118,163,1,163,118,118,176,1,118,105,176,152,118,164,43,152,145,43,119,2,71,109,141,47,41,158,44,71,177,45,109,88,45,88,146,46,47,109,141,47,27,167,50,166,49,120,165,139,121,94,5,122,50,123,51,124,157,6,102,157,123,6,100,8,178,5,167,51,6,124,52,100,178,52,53,168,125,125,165,120,54,125,168,9,48,175,120,9,125,93,10,135,181,101,56,57,169,10,59,172,61,67,170,171,67,171,127,58,127,171,129,186,113,60,61,172,61,173,112,62,112,173,174,189,129,165,64,23,64,137,23,165,22,49,64,54,168,17,114,131,17,112,114,66,133,65,19,132,133,19,133,61,134,133,66,166,134,66,166,66,167,93,135,21,68,135,121,23,136,22,94,34,139,25,96,179,26,138,69,69,179,26,30,103,176,116,141,70,39,141,116,73,142,105,143,76,37,26,35,77,103,97,76,77,144,33,33,139,77,38,151,149,80,161,45,80,45,146,81,115,8,107,155,97,82,98,107,95,151,84,38,156,85,86,116,160,96,102,24,72,29,28,29,95,74,75,30,82,108,147,36,88,44,43,91,110,51,170,67,10,11,183,131,64,14,63,89,15,53,100,7,18,112,17,19,127,134,67,136,126,21,158,41,31,33,32,81,115,80,79,177,28,29,43,2,152,71,44,109,47,46,41,141,109,47,167,5,50,123,5,51,100,53,8,125,54,165,9,120,48,93,57,10,59,58,172,174,185,189,165,54,64,165,23,22,94,26,34,30,75,103,143,104,76,26,163,35,38,85,151,192,182,191,183,128,201,12,13,89,181,169,57,186,153,113,188,183,99,184,182,63,185,13,189,180,181,93,186,99,153,189,186,129,185,184,130,186,13,12,187,93,126,193,199,194,194,196,193,200,187,195,187,197,195,187,126,197,197,190,194,190,136,137,190,196,194,63,182,192,63,192,196,192,198,196,191,182,55,193,196,198,194,199,197,195,197,199,136,197,126,190,137,63,190,63,196,197,136,190,192,191,198,201,99,183,90,55,182,181,180,101,185,130,13,186,188,99,186,189,13,187,180,93,200,101,187,183,188,131,184,185,174,180,187,101,16,18,17,12,131,188,35,42,144,163,1,162,76,162,1,79,146,145] 86 | } 87 | ], 88 | 'stones': [ 89 | { 90 | type: 'mesh', 91 | vertices: [-376,189,42,230,223,-310,353,162,-62,414,-23,-67,256,90,-475,24,85,-526,-418,-16,57,-432,66,-40,-199,151,-376,-155,49,467,-91,289,201,293,197,91,81,-17,-480,42,108,431,-359,-17,-250,383,-19,-243,194,-15,270,-272,180,293,-86,212,262,234,54,297,395,97,-302,-123,-21,-444,-416,-19,-123,-323,-18,267,-100,-16,429,-300,96,-361,163,-19,409,118,201,-431,-241,-18,391,-130,274,-309,306,-19,-399,-221,96,404], 92 | faces: [31,18,17,0,17,18,3,20,2,18,11,10,29,27,8,27,29,1,0,18,10,10,29,0,16,19,26,11,2,1,20,30,4,20,3,15,30,12,4,4,12,5,5,27,4,4,27,20,21,25,5,7,8,25,22,7,14,7,25,14,23,28,31,0,7,17,24,26,9,31,28,9,8,27,5,2,20,1,13,19,18,10,11,1,19,13,26,3,11,19,19,16,3,11,3,2,11,18,19,20,15,30,29,10,1,25,21,14,8,5,25,5,12,21,6,7,22,7,6,23,8,0,29,8,7,0,23,31,7,13,31,9,18,31,13,9,28,24,26,13,9,27,1,20,7,31,17] 93 | }, 94 | { 95 | type: 'mesh', 96 | vertices: [-217,34,-153,198,90,20,212,85,169,-131,93,171,197,113,30,173,121,164,315,29,-16,219,24,189,282,50,-102,232,38,-181,-195,-9,-166,-156,30,-207,-51,-9,-231,-180,91,-173,-19,73,-204,-280,23,96,-242,100,107,3,158,-82,109,88,221,275,-10,-40,236,-10,-135,-178,49,184,-1,-10,-243,265,-11,109,-12,-9,237,-36,46,251,-233,86,-81,93,77,-171,-163,133,69,18,16,263,296,44,93,131,-12,-226,-89,-10,-201,-273,-10,-51,-240,-9,110,190,-12,192,-253,-11,-92,42,43,-258,-115,-11,238,168,99,-88,-285,-10,24,71,124,-158,298,-10,10,116,150,-24,-282,44,39], 97 | faces: [44,16,26,13,26,16,0,26,13,27,14,41,4,5,1,7,30,2,28,5,43,41,39,27,17,43,41,43,4,39,13,28,17,17,41,13,28,43,17,24,29,38,29,35,7,18,25,29,5,18,2,18,5,3,30,42,6,30,35,23,19,20,8,8,20,9,9,39,8,1,30,8,31,37,9,11,14,37,14,27,37,32,11,12,11,37,12,11,0,13,33,40,44,44,26,33,33,0,36,34,38,15,44,40,15,21,3,16,27,39,9,2,30,1,21,25,3,16,3,28,28,3,5,4,43,5,41,43,39,13,16,28,25,21,38,38,29,25,7,18,29,29,24,35,18,7,2,18,3,25,30,23,42,30,7,35,8,30,6,6,19,8,6,42,19,8,39,1,37,31,22,27,9,37,9,20,31,10,11,32,11,10,0,12,37,22,14,13,41,14,11,13,33,26,0,36,0,10,21,44,15,16,44,21,15,40,34,38,21,15,4,1,39,5,2,1] 98 | }, 99 | { 100 | type: 'mesh', 101 | vertices: [-101,102,57,99,35,102,40,72,80,59,14,-168,-186,22,45,-176,25,-30,66,-7,146,153,-7,53,-110,47,-96,-90,-8,-146,150,-7,-12,-200,-7,8,-173,-7,-55,55,46,-60,125,-7,110,136,30,-10,-149,58,68,-15,82,-71,98,-7,-86,-34,-6,-194,-33,-7,171,-36,65,137,38,-8,-192,-103,-9,147,-12,62,-152], 102 | faces: [2,17,0,17,8,0,17,24,8,19,24,22,5,11,4,2,13,17,17,13,24,21,23,20,1,2,21,7,15,1,7,10,15,5,9,12,15,18,13,0,5,16,0,8,5,1,15,2,10,18,15,3,13,18,24,3,22,11,23,4,4,16,5,16,4,23,24,13,3,15,13,2,6,1,21,6,21,20,6,14,1,2,0,21,1,14,7,3,18,22,8,24,19,8,19,9,12,11,5,5,8,9,16,23,21,16,21,0] 103 | }, 104 | { 105 | type: 'mesh', 106 | vertices: [86,55,-18,58,38,73,97,-12,79,135,7,10,-93,-11,-72,-133,5,33,13,68,-32,94,-11,-57,-90,52,53,-24,-11,-106,-13,-10,104,-75,49,-69,-12,18,114,49,-12,-96,-46,-11,-85,-119,-11,-26,48,5,-111,-58,-11,105,-117,-12,52,-5,35,-93,123,-11,7], 107 | faces: [5,8,11,2,3,1,8,1,6,11,8,6,6,19,11,10,12,17,20,7,3,3,7,16,16,0,3,16,9,19,14,4,9,15,18,5,5,11,15,18,17,5,19,0,16,1,3,0,0,6,1,19,6,0,12,8,17,2,1,12,12,10,2,1,8,12,3,2,20,16,13,9,16,7,13,19,4,11,15,11,4,17,8,5,9,4,19] 108 | } 109 | ], 110 | 'torii': [ 111 | { 112 | type: 'mesh', 113 | mirror: true, 114 | flatShading: true, 115 | vertices: [692,966,-52,661,834,-52,692,966,52,661,834,52,0,894,-52,0,776,-52,0,894,52,0,776,52,518,935,52,345,913,52,170,899,52,162,779,52,328,790,52,494,808,52,170,899,-52,345,913,-52,518,935,-52,494,808,-52,328,790,-52,162,779,-52,0,618,16,0,697,16,0,618,-16,0,697,-16,586,618,16,586,697,16,586,618,-16,586,697,-16,331,-29,-75,331,766,-52,369,-29,-65,357,766,-45,396,-29,-37,377,766,-26,406,-29,0,384,766,0,396,-29,37,377,766,26,369,-29,65,357,766,45,331,-29,75,331,766,52,294,-29,65,305,766,45,267,-29,37,286,766,26,257,-29,0,279,766,0,267,-29,-37,286,766,-26,294,-29,-65,305,766,-45,0,777,85,0,681,33,333,762,-75,333,806,-75,371,762,-65,371,806,-65,398,762,-37,398,806,-37,408,762,0,408,806,0,398,762,37,398,806,37,371,762,65,371,806,65,333,762,75,333,806,75,296,762,65,296,806,65,268,762,37,268,806,37,258,762,0,258,806,0,268,762,-37,268,806,-37,296,762,-65,296,806,-65,0,681,-33,0,777,-85,52,681,33,52,777,85,52,681,-33,52,777,-85], 116 | faces: [4,10,14,1,13,17,11,6,7,0,3,1,16,1,17,4,19,5,14,18,19,15,17,18,3,8,13,13,9,12,12,10,11,19,7,5,19,12,11,18,13,12,16,2,0,15,8,16,14,9,15,23,26,22,27,24,26,25,20,24,26,20,22,23,25,27,29,30,28,31,32,30,33,34,32,35,36,34,37,38,36,39,40,38,41,42,40,43,44,42,45,46,44,47,48,46,49,50,48,51,28,50,55,56,54,57,58,56,59,60,58,61,62,60,63,64,62,79,81,83,65,66,64,82,53,78,67,68,66,81,53,80,69,70,68,83,80,82,71,72,70,79,82,78,73,74,72,75,63,59,75,76,74,77,54,76,60,68,76,4,6,10,1,3,13,11,10,6,0,2,3,16,0,1,4,14,19,14,15,18,15,16,17,3,2,8,13,8,9,12,9,10,19,11,7,19,18,12,18,17,13,16,8,2,15,9,8,14,10,9,23,27,26,27,25,24,25,21,20,26,24,20,23,21,25,29,31,30,31,33,32,33,35,34,35,37,36,37,39,38,39,41,40,41,43,42,43,45,44,45,47,46,47,49,48,49,51,50,51,29,28,55,57,56,57,59,58,59,61,60,61,63,62,63,65,64,79,52,81,65,67,66,82,80,53,67,69,68,81,52,53,69,71,70,83,81,80,71,73,72,79,83,82,73,75,74,59,57,55,55,77,75,75,73,71,71,69,75,67,65,63,63,61,59,59,55,75,75,69,67,67,63,75,75,77,76,77,55,54,76,54,56,56,58,76,60,62,68,64,66,68,68,70,72,72,74,68,76,58,60,62,64,68,68,74,76] 117 | } 118 | ], 119 | 'hexagons': [ 120 | {type: 'extrude', vertices: [-0.198, -0.302, 0.197, -0.3, 0.372, 0, 0.199, 0.298, -0.202, 0.298, -0.368, 0] } 121 | ], 122 | 'towers': [ 123 | {type: 'extrude', vertices: [-0.054, -0.178, -0.007, -0.182, 0.069, -0.027, 0.189, 0.079, 0.178, 0.124, -0.007, 0.097, -0.145, 0.182, -0.178, 0.144, -0.079, -0.021]}, 124 | {type: 'lathe', segments: 4, vertices: [0.004, 0.02, 0.012, 0.092, 0.042, 0.166, 0.067, 0.55, 0.101, 0.594, 0.105, 0.838, 0.193, 0.934, 0.18, 0.994]}, 125 | {type: 'lathe', segments: 5, vertices: [0.069, 0.216, 0.067, 0.562, 0.126, 0.562, 0.128, 0.774, 0.191, 0.774, 0.193, 0.986]} 126 | ], 127 | 'trees': [ 128 | {type: 'lathe', noise: 0.015, segments: 6, vertices: [0.000001, 0.826, 0.054, 0.832, 0.105, 0.854, 0.136, 0.9, 0.136, 0.958, 0.118, 0.994]}, 129 | {type: 'lathe', noise: 0.015, segments: 14, vertices: [0.000001, 0.01, 0.069, 0.022, 0.13, 0.068, 0.178, 0.18, 0.189, 0.32, 0.191, 0.59, 0.193, 0.75, 0.138, 0.79, 0.018, 0.808, 0.018, 0.996]}, 130 | {type: 'lathe', noise: 0.015, segments: 14, vertices: [0.000001, 0.436, 0.126, 0.46, 0.201, 0.57, 0.219, 0.72, 0.154, 0.846, 0.028, 0.884, 0.034, 0.996]} 131 | ], 132 | 'apparatus': [ 133 | {type: 'lathe', segments: 10, vertices: [0.000001, 0.23, 0.042, 0.23, 0.069, 0.36, 0.038, 0.362, 0.038, 0.372, 0.06, 0.372, 0.073, 0.572, 0.024, 0.572, 0.024, 0.67, 0.069, 0.67, 0.075, 0.722, 0.097, 0.724, 0.105, 0.852, 0.083, 0.902, 0.065, 0.902, 0.065, 0.924, 0.128, 0.924, 0.146, 0.996]}, 134 | {type: 'lathe', segments: 16, vertices: [0.000001, 0.232, 0.229, 0.182, 0.486, 0.07, 0.356, 0.182, 0.213, 0.242, 0.154, 0.242, 0.144, 0.262, 0.178, 0.262, 0.126, 0.314, 0.04, 0.328, 0.038, 0.374, 0.058, 0.374, 0.071, 0.408, 0.026, 0.406, 0.03, 0.42, 0.091, 0.418, 0.034, 0.496, 0.01, 0.498, 0.03, 0.506, 0.014, 0.998]}, 135 | ], 136 | 'mushrooms': [ 137 | {type: 'lathe', noise: 0.02, segments: 14, vertices: [0.000001, 0.006, 0.13, 0.018, 0.341, 0.084, 0.437, 0.144, 0.492, 0.234, 0.484, 0.246, 0.276, 0.232, 0.107, 0.284, 0.046, 0.346, 0.062, 0.852, 0.097, 0.956, 0.166, 0.998]}, 138 | {type: 'lathe', noise: 0.02, segments: 10, vertices: [0.000001, 0.562, 0.091, 0.572, 0.172, 0.61, 0.223, 0.666, 0.256, 0.74, 0.258, 0.806, 0.246, 0.824, 0.062, 0.826, 0.065, 0.948, 0.097, 0.998]}, 139 | {type: 'lathe', noise: 0.02, segments: 10, vertices: [0.000001, 0.768, 0.099, 0.772, 0.219, 0.802, 0.306, 0.844, 0.352, 0.886, 0.352, 0.908, 0.118, 0.904, 0.107, 0.93, 0.115, 0.966, 0.14, 0.996]} 140 | ] 141 | }; 142 | 143 | // scale down dressing meshes (coordinates were saved in integers for better compression) 144 | for (var i in this.assets){ 145 | for (var j = 0; j < this.assets[i].length; j++) { 146 | var asset = this.assets[i][j]; 147 | if (asset.type != 'mesh') continue; 148 | for (var v = 0, len = asset.vertices.length; v < len; v++) { 149 | asset.vertices[v] /= 1000.0; 150 | } 151 | } 152 | } 153 | 154 | // save current scene fog 155 | this.userFog = this.el.sceneEl.getAttribute('fog'); 156 | 157 | // create sky 158 | this.sky = document.createElement('a-sky'); 159 | this.sky.setAttribute('radius', this.STAGE_SIZE); 160 | this.sky.setAttribute('theta-length', 110); 161 | this.sky.classList.add('environment'); 162 | 163 | // stars are created when needed 164 | this.stars = null; 165 | 166 | // create ground 167 | this.ground = document.createElement('a-entity'); 168 | this.ground.setAttribute('rotation', '-90 0 0'); 169 | this.ground.classList.add('environmentGround'); 170 | this.ground.classList.add('environment'); 171 | this.groundCanvas = null; 172 | this.groundTexture = null; 173 | this.groundMaterial = null; 174 | this.groundGeometry = null; 175 | 176 | this.dressing = document.createElement('a-entity'); 177 | this.dressing.classList.add('environmentDressing'); 178 | this.dressing.classList.add('environment'); 179 | 180 | this.gridCanvas = null; 181 | this.gridTexture = null; 182 | 183 | // create lights (one ambient hemisphere light, and one directional for the sun) 184 | this.hemilight = document.createElement('a-entity'); 185 | this.hemilight.classList.add('environment'); 186 | this.hemilight.setAttribute('position', '0 50 0'); 187 | this.hemilight.setAttribute('light', { 188 | type: 'hemisphere', 189 | color: '#CEE4F0', 190 | intensity: 1.256 191 | }); 192 | this.sunlight = document.createElement('a-entity'); 193 | this.sunlight.classList.add('environment'); 194 | this.sunlight.setAttribute('position', this.data.lightPosition); 195 | this.sunlight.setAttribute('light', {intensity: 1.884}); 196 | 197 | // add everything to the scene 198 | this.el.appendChild(this.hemilight); 199 | this.el.appendChild(this.sunlight); 200 | this.el.appendChild(this.ground); 201 | this.el.appendChild(this.dressing); 202 | this.el.appendChild(this.sky); 203 | }, 204 | 205 | // returns a fog color from a specific sky type and sun height 206 | getFogColor: function (skyType, sunHeight) { 207 | 208 | // Note: linear operations are performed on the sRGB fog color 209 | // so tell Three that it's NoColorSpace and let it convert 210 | // to the working color space after all computations are done 211 | var fogColor; 212 | if (skyType == 'color' || skyType == 'none'){ 213 | fogColor = new THREE.Color().setStyle(this.environmentData.skyColor, THREE.NoColorSpace); 214 | } 215 | else if (skyType == 'gradient'){ 216 | fogColor = new THREE.Color().setStyle(this.environmentData.horizonColor, THREE.NoColorSpace); 217 | } 218 | else if (skyType == 'atmosphere') 219 | { 220 | var fogRatios = [ 1, 0.5, 0.22, 0.1, 0.05, 0]; 221 | var fogColors = ['#C0CDCF', '#81ADC5', '#525e62', '#2a2d2d', '#141616', '#000']; 222 | 223 | if (sunHeight <= 0) return '#000'; 224 | 225 | sunHeight = Math.min(1, sunHeight); 226 | 227 | for (var i = 0; i < fogRatios.length; i++){ 228 | if (sunHeight > fogRatios[i]) { 229 | var c1 = new THREE.Color().setStyle(fogColors[i - 1], THREE.NoColorSpace); 230 | var c2 = new THREE.Color().setStyle(fogColors[i], THREE.NoColorSpace); 231 | var a = (sunHeight - fogRatios[i]) / (fogRatios[i - 1] - fogRatios[i]); 232 | c2.lerp(c1, a); 233 | fogColor = c2; 234 | break; 235 | } 236 | } 237 | } 238 | // dim down the color 239 | fogColor.multiplyScalar(0.9); 240 | // mix it a bit with ground color 241 | fogColor.lerp(new THREE.Color().setStyle(this.data.groundColor, THREE.NoColorSpace), 0.3); 242 | 243 | // convert the resulting color to the working color space 244 | fogColor.setRGB(fogColor.r, fogColor.g, fogColor.b, THREE.SRGBColorSpace); 245 | 246 | return '#' + fogColor.getHexString(); 247 | }, 248 | 249 | update: function (oldDataNonPreset) { 250 | var oldData; 251 | 252 | if (!this.data.preset) { 253 | oldData = oldDataNonPreset; 254 | this.environmentData = this.data; 255 | } else { 256 | oldData = AFRAME.utils.clone(this.environmentData); 257 | this.environmentData = {}; 258 | Object.assign(this.environmentData, this.data); 259 | Object.assign(this.environmentData, this.presets[this.data.preset]); 260 | Object.assign(this.environmentData, this.el.components.environment.attrValue); 261 | console.log(this.environmentData); 262 | } 263 | 264 | var skyType = this.environmentData.skyType; 265 | var sunPos = new THREE.Vector3(this.environmentData.lightPosition.x, this.environmentData.lightPosition.y, this.environmentData.lightPosition.z); 266 | sunPos.normalize(); 267 | 268 | // update light colors and intensities 269 | if (this.sunlight) { 270 | this.sunlight.setAttribute('position', this.environmentData.lightPosition); 271 | if (skyType != 'atmosphere') { 272 | // dim down the sky color for the light 273 | var skycol = new THREE.Color().setStyle(this.environmentData.skyColor, THREE.NoColorSpace); 274 | skycol.setRGB( 275 | (skycol.r + 1.0) / 2.0, 276 | (skycol.g + 1.0) / 2.0, 277 | (skycol.b + 1.0) / 2.0, 278 | THREE.SRGBColorSpace 279 | ); 280 | this.hemilight.setAttribute('light', { 281 | 'color': '#' + skycol.getHexString(), 282 | 'intensity': 1.884 283 | }); 284 | this.sunlight.setAttribute('light', {'intensity': 1.884}); 285 | } 286 | else { 287 | this.hemilight.setAttribute('light', { 288 | 'color': '#CEE4F0', 289 | 'intensity': 0.314 + sunPos.y * 1.57 290 | }); 291 | this.sunlight.setAttribute('light', {'intensity': 0.314 + sunPos.y * 1.57}); 292 | } 293 | 294 | this.sunlight.setAttribute('light', { 295 | castShadow: this.environmentData.shadow, 296 | shadowCameraLeft: -this.environmentData.shadowSize, 297 | shadowCameraBottom: -this.environmentData.shadowSize, 298 | shadowCameraRight: this.environmentData.shadowSize, 299 | shadowCameraTop: this.environmentData.shadowSize 300 | }); 301 | } 302 | 303 | var updateStageSize = this.environmentData.stageSize !== oldData.stageSize; 304 | 305 | if (updateStageSize) { 306 | this.STAGE_SIZE = this.data.stageSize; 307 | this.sky.setAttribute('radius', this.STAGE_SIZE); 308 | } 309 | // update sky colors 310 | if (skyType !== oldData.skyType || 311 | this.environmentData.skyColor != oldData.skyColor || 312 | this.environmentData.horizonColor != oldData.horizonColor) { 313 | 314 | var mat = {}; 315 | mat.shader = {'none': 'flat', 'color': 'flat', 'gradient': 'gradientshader', 'atmosphere': 'skyshader'}[skyType]; 316 | if (this.stars) { 317 | this.stars.setAttribute('visible', skyType == 'atmosphere'); 318 | } 319 | if (skyType == 'color') { 320 | mat.color = this.environmentData.skyColor; 321 | mat.fog = false; 322 | } 323 | else if (skyType == 'gradient') { 324 | // Gradient shader doesn't encode fragments, so pass in colors as NoColorSpace 325 | mat.topColor = new THREE.Color().setStyle(this.environmentData.skyColor, THREE.NoColorSpace); 326 | mat.bottomColor = new THREE.Color().setStyle(this.environmentData.horizonColor, THREE.NoColorSpace); 327 | } 328 | 329 | this.sky.setAttribute('material', mat); 330 | } 331 | 332 | // set atmosphere sun position and stars 333 | if (skyType == 'atmosphere') { 334 | this.sky.setAttribute('material', {'sunPosition': sunPos}); 335 | this.setStars((1 - Math.max(0, (sunPos.y + 0.08) * 8)) * 2000 ); 336 | } 337 | 338 | // set fog color 339 | if (this.environmentData.fog > 0) { 340 | this.el.sceneEl.setAttribute('fog', { 341 | color: this.getFogColor(skyType, sunPos.y), 342 | far: (1.01 - this.environmentData.fog) * this.STAGE_SIZE * 2 343 | }); 344 | } 345 | else { 346 | this.el.sceneEl.removeAttribute('fog'); 347 | } 348 | 349 | // scene lights 350 | this.sunlight.setAttribute('light', {type: this.environmentData.lighting == 'point' ? 'point' : 'directional'}); 351 | this.sunlight.setAttribute('visible', this.environmentData.lighting !== 'none'); 352 | this.hemilight.setAttribute('visible', this.environmentData.lighting !== 'none'); 353 | 354 | // check if ground geometry needs to be calculated 355 | var updateGroundGeometry = 356 | !this.groundGeometry || 357 | this.environmentData.seed != oldData.seed || 358 | this.environmentData.ground != oldData.ground || 359 | this.environmentData.playArea != oldData.playArea || 360 | this.environmentData.flatShading != oldData.flatShading || 361 | this.environmentData.groundDensity != oldData.groundDensity || 362 | this.environmentData.groundFrequency != oldData.groundFrequency || 363 | updateStageSize; 364 | 365 | // check if any parameter of the ground was changed, and update it 366 | if (updateGroundGeometry || 367 | this.environmentData.groundColor != oldData.groundColor || 368 | this.environmentData.groundColor2 != oldData.groundColor2 || 369 | this.environmentData.groundYScale != oldData.groundYScale || 370 | this.environmentData.groundTexture != oldData.groundTexture || 371 | this.environmentData.gridColor != oldData.gridColor || 372 | this.environmentData.grid != oldData.grid 373 | ) 374 | { 375 | this.updateGround(updateGroundGeometry); 376 | // set bounce light color to ground color 377 | if (this.hemilight) this.hemilight.setAttribute('light', {'groundColor': this.environmentData.groundColor}); 378 | } 379 | 380 | // update dressing 381 | if (this.environmentData.seed != oldData.seed || 382 | this.environmentData.dressingOnPlayArea != oldData.dressingOnPlayArea || 383 | this.environmentData.dressing != oldData.dressing || 384 | this.environmentData.flatShading != oldData.flatShading || 385 | this.environmentData.dressingAmount != oldData.dressingAmount || 386 | this.environmentData.dressingScale != oldData.dressingScale || 387 | this.environmentData.dressingColor != oldData.dressingColor || 388 | this.environmentData.dressingVariance.x != oldData.dressingVariance.x || 389 | this.environmentData.dressingVariance.y != oldData.dressingVariance.y || 390 | this.environmentData.dressingVariance.z != oldData.dressingVariance.z || 391 | this.environmentData.dressingUniformScale != oldData.dressingUniformScale || 392 | updateStageSize 393 | ) { 394 | this.updateDressing(); 395 | } 396 | 397 | this.sky.setAttribute('visible', skyType !== 'none'); 398 | 399 | this.el.setAttribute('visible', this.environmentData.active); 400 | if (!this.environmentData.active) { 401 | if (this.userFog) { 402 | this.el.sceneEl.setAttribute('fog', this.userFog); 403 | } 404 | else { 405 | this.el.sceneEl.removeAttribute('fog'); 406 | } 407 | } 408 | 409 | // dump current component settings to console 410 | this.dumpParametersDiff(); 411 | }, 412 | 413 | remove: function() { 414 | if (this.userFog) { 415 | this.el.sceneEl.setAttribute('fog', this.userFog); 416 | } 417 | else { 418 | this.el.sceneEl.removeAttribute('fog'); 419 | } 420 | this.el.removeChild(this.hemilight); 421 | this.el.removeChild(this.sunlight); 422 | if (this.groundTexture) this.groundTexture.dispose(); 423 | if (this.gridTexture) this.gridTexture.dispose(); 424 | if (this.groundMaterial) this.groundMaterial.dispose(); 425 | if (this.groundGeometry) this.groundGeometry.dispose(); 426 | this.el.removeChild(this.ground); 427 | var dressingMesh = this.dressing.getObject3D('mesh'); 428 | if (dressingMesh && dressingMesh.children.length > 0) { 429 | dressingMesh.children[0].material.dispose(); 430 | dressingMesh.children[0].geometry.dispose(); 431 | } 432 | this.el.removeChild(this.dressing); 433 | this.el.removeChild(this.sky); 434 | this.removeStars(); 435 | }, 436 | 437 | // logs current parameters to console, for saving to a preset 438 | logPreset: function () { 439 | var str = '{'; 440 | for (var i in this.schema){ 441 | if (i == 'preset') continue; 442 | str += i + ': '; 443 | var type = this.schema[i].type; 444 | if (type == 'vec3') { 445 | str += '{ x: ' + this.environmentData[i].x + ', y: ' + this.environmentData[i].y + ', z: ' + this.environmentData[i].z + '}'; 446 | } 447 | else if (type == 'string' || type == 'color') { 448 | str += '"' + this.environmentData[i] + '"'; 449 | } 450 | else { 451 | str += this.environmentData[i]; 452 | } 453 | str += ', '; 454 | } 455 | str += '}'; 456 | console.log(str); 457 | }, 458 | 459 | // dumps current component settings to console. 460 | dumpParametersDiff: function () { 461 | 462 | // trim number to 3 decimals 463 | function dec3 (v) { 464 | return Math.floor(v * 1000) / 1000; 465 | } 466 | 467 | var params = []; 468 | var usingPreset = this.data.preset != 'none' ? this.presets[this.data.preset] : false; 469 | 470 | if (usingPreset) { 471 | params.push('preset: ' + this.data.preset); 472 | } 473 | 474 | for (var i in this.schema) { 475 | if (i == 'preset' || (usingPreset && usingPreset[i] === undefined)) { 476 | continue; 477 | } 478 | var def = usingPreset ? usingPreset[i] : this.schema[i].default; 479 | var data = this.environmentData[i]; 480 | var type = this.schema[i].type; 481 | if (type == 'vec3') { 482 | var coords = def; 483 | if (typeof(def) == 'string') { 484 | def = def.split(' '); 485 | coords = {x: def[0], y: def[1], z: def[2]}; 486 | } 487 | if (dec3(coords.x) != dec3(data.x) || dec3(coords.y) != dec3(data.y) || dec3(coords.z) != dec3(data.z)) { 488 | params.push(i + ': ' + dec3(data.x) + ' ' + dec3(data.y) + ' ' + dec3(data.z)); 489 | } 490 | } 491 | else { 492 | if (def != data) { 493 | if (this.schema[i].type == 'number') { 494 | data = dec3(data); 495 | } 496 | params.push(i + ': ' + data); 497 | } 498 | } 499 | } 500 | console.log('%c' + params.join('; '), 'color: #f48;font-weight:bold'); 501 | }, 502 | 503 | // Custom Math.random() with seed. Given this.environmentData.seed and x, it always returns the same "random" number 504 | random: function (x) { 505 | return parseFloat('0.' + Math.sin(this.environmentData.seed * 9999 * x).toString().substr(7)); 506 | }, 507 | 508 | 509 | // updates ground attributes, and geometry if required 510 | updateGround: function (updateGeometry) { 511 | 512 | var resolution = this.environmentData.groundDensity; // number of divisions of the ground mesh 513 | 514 | if (updateGeometry) { 515 | var visibleground = this.environmentData.ground != 'none'; 516 | this.ground.setAttribute('visible', visibleground); 517 | if (!visibleground) { 518 | return; 519 | } 520 | 521 | if (!this.groundGeometry) { 522 | this.groundGeometry = new THREE.PlaneGeometry(this.STAGE_SIZE + 2, this.STAGE_SIZE + 2, resolution - 1, resolution - 1); 523 | } 524 | var perlin = new PerlinNoise(this.environmentData.seed); 525 | var verts = this.groundGeometry.attributes.position.array; 526 | var numVerts = verts.length; 527 | var frequency = this.environmentData.groundFrequency; 528 | var inc = frequency / resolution; 529 | var x = 0; 530 | var y = 0; 531 | 532 | for (var i = 2; i < numVerts; i+=3) { 533 | if (this.environmentData.ground == 'flat') { 534 | verts[i] = 0; 535 | continue; 536 | } 537 | 538 | var h; 539 | switch (this.environmentData.ground) { 540 | case 'hills': { 541 | h = Math.max(0, perlin.noise(x, y, 0)); 542 | break; 543 | } 544 | case 'canyon': { 545 | h = 0.2 + perlin.noise(x, y, 0) * 0.8; 546 | h = Math.min(1, Math.pow(h, 2) * 10); 547 | break; 548 | } 549 | case 'spikes': { 550 | h = this.random(i) < 0.02 ? this.random(i + 1) : 0; 551 | break; 552 | } 553 | case 'noise': { 554 | h = this.random(i) < 0.35 ? this.random(i + 1) : 0; 555 | break; 556 | } 557 | } 558 | 559 | h += this.random(i + 2) * 0.1; // add some randomness 560 | 561 | // flat ground in the center 562 | var xx = x * 2 / frequency - 1; 563 | var yy = y * 2 / frequency - 1; 564 | var pa = this.environmentData.playArea; 565 | xx = Math.max(0, Math.min(1, (Math.abs(xx) - (pa - 0.9)) * (1 / pa) )); 566 | yy = Math.max(0, Math.min(1, (Math.abs(yy) - (pa - 0.9)) * (1 / pa) )); 567 | h *= xx > yy ? xx : yy; 568 | if (h < 0.01) h = 0; // stick to the floor 569 | 570 | // set height 571 | verts[i] = h; 572 | 573 | // calculate next x,y ground coordinates 574 | x += inc; 575 | if (x >= frequency) { 576 | x = 0; 577 | y += inc; 578 | } 579 | } 580 | 581 | this.groundGeometry.computeVertexNormals(); 582 | 583 | this.groundGeometry.attributes.position.needsUpdate = true; 584 | this.groundGeometry.attributes.normal.needsUpdate = true; 585 | } 586 | 587 | // apply Y scale. There's no need to recalculate the geometry for this. Just change scale 588 | this.ground.setAttribute('scale', {z: this.environmentData.groundYScale}); 589 | 590 | // update ground, playarea and grid textures. 591 | var groundResolution = 2048; 592 | var texMeters = 20; // ground texture of 20 x 20 meters 593 | var texRepeat = this.STAGE_SIZE / texMeters; 594 | 595 | if (!this.groundCanvas || this.groundCanvas.width != groundResolution) { 596 | this.gridCanvas = document.createElement('canvas'); 597 | this.gridCanvas.width = groundResolution; 598 | this.gridCanvas.height = groundResolution; 599 | this.gridTexture = new THREE.Texture(this.gridCanvas); 600 | this.gridTexture.wrapS = THREE.RepeatWrapping; 601 | this.gridTexture.wrapT = THREE.RepeatWrapping; 602 | this.gridTexture.repeat.set(texRepeat, texRepeat); 603 | this.gridTexture.anisotropy = 4; 604 | this.rendererSystem.applyColorCorrection(this.gridTexture); 605 | 606 | this.groundCanvas = document.createElement('canvas'); 607 | this.groundCanvas.width = groundResolution; 608 | this.groundCanvas.height = groundResolution; 609 | this.groundTexture = new THREE.Texture(this.groundCanvas); 610 | this.groundTexture.wrapS = THREE.RepeatWrapping; 611 | this.groundTexture.wrapT = THREE.RepeatWrapping; 612 | this.groundTexture.repeat.set(texRepeat, texRepeat); 613 | this.groundTexture.anisotropy = 4; 614 | this.rendererSystem.applyColorCorrection(this.groundTexture); 615 | 616 | // ground material diffuse map is the regular ground texture and the grid texture 617 | // is used in the emissive map. This way, the grid is always equally visible, even at night. 618 | this.groundMaterialProps = { 619 | map: this.groundTexture, 620 | emissive: new THREE.Color(0xFFFFFF), 621 | emissiveMap: this.gridTexture 622 | }; 623 | 624 | this.groundMaterialProps.flatShading = this.environmentData.flatShading; 625 | 626 | this.groundMaterial = new THREE.MeshLambertMaterial(this.groundMaterialProps); 627 | } 628 | 629 | var groundctx = this.groundCanvas.getContext('2d'); 630 | var gridctx = this.gridCanvas.getContext('2d'); 631 | 632 | this.drawTexture(groundctx, groundResolution, texMeters); 633 | 634 | gridctx.fillStyle = '#000000'; 635 | gridctx.fillRect(0, 0, groundResolution, groundResolution); 636 | this.drawGrid(gridctx, groundResolution, texMeters); 637 | 638 | this.groundTexture.needsUpdate = true; 639 | this.gridTexture.needsUpdate = true; 640 | 641 | if (updateGeometry) { 642 | var mesh = new THREE.Mesh(this.groundGeometry, this.groundMaterial); 643 | this.ground.setObject3D('mesh', mesh); 644 | } 645 | else { 646 | this.ground.getObject3D('mesh').material = this.groundMaterial; 647 | } 648 | 649 | this.ground.setAttribute('shadow', { 650 | cast: false, 651 | receive: this.environmentData.shadow 652 | }); 653 | }, 654 | 655 | // draw grid to a canvas context 656 | drawGrid: function (ctx, size, texMeters) { 657 | 658 | if (this.environmentData.grid == 'none') return; 659 | 660 | // one grid feature each 2 meters 661 | 662 | var num = Math.floor(texMeters / 2); 663 | var step = size / (texMeters / 2); // 2 meters == pixels 664 | var i, j, ii; 665 | 666 | ctx.fillStyle = this.environmentData.gridColor; 667 | 668 | switch (this.environmentData.grid) { 669 | case '1x1': 670 | case '2x2': { 671 | if (this.environmentData.grid == '1x1') { 672 | num = num * 2; 673 | step = size / texMeters; 674 | } 675 | for (i = 0; i < num; i++) { 676 | ii = Math.floor(i * step); 677 | ctx.fillRect(0, ii, size, 1); 678 | ctx.fillRect(ii, 0, 1, size); 679 | } 680 | break; 681 | } 682 | case 'crosses': { 683 | var l = Math.floor(step / 20); 684 | for (i = 0; i < num + 1; i++) { 685 | ii = Math.floor(i * step); 686 | for (j = 0; j < num + 1; j++) { 687 | var jj = Math.floor(-l + j * step); 688 | ctx.fillRect(jj, ii, l * 2, 1); 689 | ctx.fillRect(ii, jj, 1, l * 2); 690 | } 691 | } 692 | break; 693 | } 694 | case 'dots': { 695 | for (i = 0; i < num + 1; i++) { 696 | for (j = 0; j < num + 1; j++) { 697 | ctx.beginPath(); ctx.arc(Math.floor(j * step), Math.floor(i * step), 4, 0, Math.PI * 2); ctx.fill(); 698 | } 699 | } 700 | break; 701 | } 702 | case 'xlines': { 703 | for (i = 0; i < num; i++) { 704 | ctx.fillRect(Math.floor(i * step), 0, 1, size); 705 | } 706 | break; 707 | } 708 | case 'ylines': { 709 | for (i = 0; i < num; i++) { 710 | ctx.fillRect(0, Math.floor(i * step), size, 1); 711 | } 712 | break; 713 | } 714 | } 715 | }, 716 | 717 | // draw ground texture to a canvas context 718 | drawTexture: function(ctx, size, texMeters) { 719 | // fill all with ground Color 720 | ctx.fillStyle = this.environmentData.groundColor; 721 | ctx.fillRect(0, 0, size, size); 722 | 723 | var i, col, col1, col2, im, imdata, numpixels; 724 | 725 | if (this.environmentData.groundTexture == 'none') return; 726 | switch(this.environmentData.groundTexture) { 727 | case 'checkerboard': { 728 | ctx.fillStyle = this.environmentData.groundColor2; 729 | var num = Math.floor(texMeters / 2); 730 | var step = size / (texMeters / 2); // 2 meters == pixels 731 | for (i = 0; i < num + 1; i += 2) { 732 | for (var j = 0; j < num + 1; j ++) { 733 | ctx.fillRect(Math.floor((i + j % 2) * step), Math.floor(j * step), Math.floor(step), Math.floor(step)); 734 | } 735 | } 736 | break; 737 | } 738 | case 'squares': { 739 | var numSquares = 16; 740 | var squareSize = size / numSquares; 741 | // Note: use THREE.NoColorSpace to perform operations on sRGB colors directly 742 | col1 = new THREE.Color().setStyle(this.environmentData.groundColor, THREE.NoColorSpace); 743 | col2 = new THREE.Color().setStyle(this.environmentData.groundColor2, THREE.NoColorSpace); 744 | for (i = 0; i < numSquares * numSquares; i++) { 745 | col = this.random(i + 3) > 0.5 ? col1.clone() : col2.clone(); 746 | col.addScalar(this.random(i + 3) * 0.1 - 0.05); 747 | ctx.fillStyle = '#' + col.getHexString(THREE.NoColorSpace); 748 | 749 | ctx.fillRect((i % numSquares) * squareSize, Math.floor(i / numSquares) * squareSize, squareSize, squareSize); 750 | } 751 | break; 752 | } 753 | case 'noise': { 754 | // TODO: fix 755 | imdata = ctx.getImageData(0, 0, size, size); 756 | im = imdata.data; 757 | // Note: use THREE.NoColorSpace to perform operations on sRGB colors directly 758 | col1 = new THREE.Color().setStyle(this.environmentData.groundColor, THREE.NoColorSpace); 759 | col2 = new THREE.Color().setStyle(this.environmentData.groundColor2, THREE.NoColorSpace); 760 | var diff = new THREE.Color(col2.r - col1.r, col2.g - col1.g, col2.b - col1.b); 761 | var perlin = new PerlinNoise(); 762 | for (i = 0, j = 0, numpixels = im.length; i < numpixels; i += 4, j++){ 763 | var rnd = perlin.noise((j % size) / size * 3, j / size / size * 3, 0); 764 | im[i + 0] = Math.floor((col1.r + diff.r * rnd) * 255); 765 | im[i + 1] = Math.floor((col1.g + diff.g * rnd) * 255); 766 | im[i + 2] = Math.floor((col1.b + diff.b * rnd) * 255); 767 | } 768 | ctx.putImageData(imdata, 0, 0); 769 | break; 770 | } 771 | case 'walkernoise': { 772 | var s = Math.floor(size / 2); 773 | var tex = document.createElement('canvas'); 774 | tex.width = s; 775 | tex.height = s; 776 | var texctx = tex.getContext('2d'); 777 | texctx.fillStyle = this.environmentData.groundColor; 778 | texctx.fillRect(0, 0, s, s); 779 | imdata = texctx.getImageData(0, 0, s, s); 780 | im = imdata.data; 781 | // Note: use THREE.NoColorSpace to perform operations on sRGB colors directly 782 | col1 = new THREE.Color().setStyle(this.environmentData.groundColor, THREE.NoColorSpace); 783 | col2 = new THREE.Color().setStyle(this.environmentData.groundColor2, THREE.NoColorSpace); 784 | var walkers = []; 785 | var numwalkers = 1000; 786 | for (i = 0; i < numwalkers; i++) { 787 | col = col1.clone().lerp(col2, Math.random()); 788 | walkers.push({ 789 | x: Math.random() * s, 790 | y: Math.random() * s, 791 | r: Math.floor(col.r * 255), 792 | g: Math.floor(col.g * 255), 793 | b: Math.floor(col.b * 255) 794 | }); 795 | } 796 | var iterations = 5000; 797 | for (var it = 0; it< iterations; it++){ 798 | for (i = 0; i < numwalkers; i++) { 799 | var walker = walkers[i]; 800 | var pos = Math.floor((walker.y * s + walker.x)) * 4; 801 | im[pos + 0] = walker.r; 802 | im[pos + 1] = walker.g; 803 | im[pos + 2] = walker.b; 804 | walker.x += Math.floor(Math.random() * 3) - 1; 805 | walker.y += Math.floor(Math.random() * 3) - 1; 806 | if (walker.x >= s) walker.x = walker.x - s; 807 | if (walker.y >= s) walker.y = walker.y - s; 808 | if (walker.x < 0) walker.x = s + walker.x; 809 | if (walker.y < 0) walker.y = s + walker.y; 810 | } 811 | } 812 | texctx.putImageData(imdata, 0, 0); 813 | ctx.drawImage(tex, 0, 0, size, size); 814 | break; 815 | } 816 | } 817 | }, 818 | 819 | // returns an array of THREE.Geometry for set dressing 820 | getAssetGeometry: function(data) { 821 | if (!data) return null; 822 | var geoset = []; 823 | var self = this; 824 | function applyNoise(geo, noise) { 825 | var verts = geo.attributes.position.array; 826 | var numVerts = verts.length; 827 | for (var i = 0; i < numVerts; i+=3) { 828 | verts[i] = (self.random(i) - 0.5) * noise; 829 | verts[i+1] = (self.random(i + numVerts) - 0.5) * noise; 830 | verts[i+2] = (self.random(i + numVerts * 2) - 0.5) * noise; 831 | } 832 | geo.attributes.position.needsUpdate = true; 833 | } 834 | 835 | var i, geo, verts; 836 | 837 | for (var j = 0; j < data.length; j++) { 838 | 839 | if (data[j].type == 'lathe') { 840 | var maxy = -99999; 841 | var points = []; 842 | verts = data[j].vertices; 843 | for (i = 0; i < verts.length; i += 2) { 844 | points.push(new THREE.Vector2(verts[i], verts[i + 1])); 845 | if (verts[i + 1] > maxy) { 846 | maxy = verts[i + 1]; 847 | } 848 | } 849 | geo = new THREE.LatheGeometry(points, data[j]['segments'] || 8); 850 | geo.applyMatrix4(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(-Math.PI, 0, 0))); 851 | geo.applyMatrix4(new THREE.Matrix4().makeTranslation(0, maxy, 0)); 852 | //if (data[j]['noise']) applyNoise(geo, data[j].noise); 853 | geo = geo.toNonIndexed(); 854 | geoset.push(geo); 855 | } 856 | 857 | else if (data[j].type == 'extrude') { 858 | var shape = new THREE.Shape(); 859 | verts = data[j].vertices; 860 | for (i = 0; i < verts.length; i+= 2) { 861 | if (i == 0) shape.moveTo(verts[i], verts[i + 1]); 862 | else shape.lineTo(verts[i], verts[i + 1]); 863 | } 864 | geo = new THREE.ExtrudeGeometry(shape, {amount: 1, bevelEnabled: false}); 865 | geo.applyMatrix4(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(-Math.PI / 2, 0, 0))); 866 | if (data[j]['noise']) applyNoise(geo, data[j].noise); 867 | geoset.push(geo); 868 | } 869 | 870 | else if (data[j].type == 'mesh') { 871 | geo = new THREE.BufferGeometry(); 872 | verts = data[j].vertices; 873 | var faces = data[j].faces; 874 | var positions = new Float32Array(verts); 875 | 876 | geo.setIndex(faces); 877 | geo.setAttribute('position', new THREE.BufferAttribute(positions, 3)); 878 | 879 | if (data[j]['mirror']) { 880 | var mirroredGeo = geo.clone(); 881 | mirroredGeo.applyMatrix4(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(0, Math.PI, 0))); 882 | var mergeGeometries = THREE.BufferGeometryUtils.mergeGeometries || THREE.BufferGeometryUtils.mergeBufferGeometries; 883 | geo = mergeGeometries([geo, mirroredGeo]); 884 | } 885 | 886 | if (data[j]['noise']) applyNoise(geo, data[j].noise); 887 | 888 | geo = geo.toNonIndexed(); 889 | geo.computeVertexNormals(); 890 | geoset.push(geo); 891 | } 892 | } 893 | return geoset; 894 | }, 895 | 896 | // updates set dressing 897 | updateDressing: function () { 898 | var dressing = new THREE.Object3D(); 899 | var geometries = []; 900 | this.dressing.setAttribute('visible', this.environmentData.dressing != 'none'); 901 | if (this.environmentData.dressing == 'none') { 902 | return; 903 | } 904 | 905 | // get array of geometries 906 | var geoset; 907 | switch (this.environmentData.dressing){ 908 | case 'cubes': { 909 | geoset = [new THREE.BoxGeometry(1, 1, 1)]; 910 | geoset[0].applyMatrix4(new THREE.Matrix4().makeTranslation(0, 0.5, 0)); 911 | break; 912 | } 913 | case 'pyramids': { 914 | geoset = [new THREE.ConeGeometry(1, 1, 4, 1, true)]; 915 | geoset[0].applyMatrix4(new THREE.Matrix4().makeTranslation(0, 0.5, 0)); 916 | break; 917 | } 918 | case 'cylinders': { 919 | geoset = [new THREE.CylinderGeometry(0.5, 0.5, 1, 8, 1, true)]; 920 | geoset[0].applyMatrix4(new THREE.Matrix4().makeTranslation(0, 0.5, 0)); 921 | break; 922 | } 923 | default: { 924 | geoset = this.getAssetGeometry(this.assets[this.environmentData.dressing]); 925 | if (!geoset) return; 926 | break; 927 | } 928 | } 929 | 930 | for (var i = 0, r = 88343; i < this.environmentData.dressingAmount; i++, r++) { 931 | 932 | var geo = geoset[Math.floor(this.random(33 + i) * geoset.length)].clone(); 933 | 934 | // set random position, rotation and scale 935 | var ds = this.environmentData.dressingScale; 936 | var dv = new THREE.Vector3(this.environmentData.dressingVariance.x, this.environmentData.dressingVariance.y, this.environmentData.dressingVariance.z); 937 | var distance; 938 | var onPlayArea = this.random(r) < this.environmentData.dressingOnPlayArea; 939 | if (onPlayArea) { 940 | distance = this.random(r + 1) * 15; 941 | } 942 | else { 943 | distance = 10 + Math.max(dv.x, dv.z) + 10 * this.random(r + 1) + this.random(r + 2) * this.STAGE_SIZE / 3; 944 | } 945 | 946 | var direction = this.random(r + 3) * Math.PI * 2; 947 | var matrix = new THREE.Matrix4(); 948 | var scale = this.random(r + 4); 949 | var uniformScale = this.environmentData.dressingUniformScale; 950 | 951 | matrix.compose( 952 | // position 953 | new THREE.Vector3( 954 | Math.cos(direction) * distance, 955 | 0, 956 | Math.sin(direction) * distance 957 | ), 958 | // rotation 959 | new THREE.Quaternion().setFromAxisAngle( 960 | new THREE.Vector3(0, 1, 0), 961 | (this.random(r + 5) - 0.5) * dv.length() * Math.PI * 2 962 | ), 963 | // scale 964 | new THREE.Vector3( 965 | ds + (uniformScale ? scale : this.random(r + 6)) * dv.x, 966 | ds + (uniformScale ? scale : this.random(r + 7)) * dv.y, 967 | ds + (uniformScale ? scale : this.random(r + 8)) * dv.z 968 | ) 969 | ); 970 | geo.applyMatrix4(matrix); 971 | geometries.push(geo); 972 | } 973 | 974 | // convert geometry to buffergeometry 975 | var mergeGeometries = THREE.BufferGeometryUtils.mergeGeometries || THREE.BufferGeometryUtils.mergeBufferGeometries; 976 | var bufgeo = mergeGeometries(geometries); 977 | bufgeo.attributes.position.needsUpdate = true; 978 | 979 | // setup Material 980 | var material = new THREE.MeshLambertMaterial({ 981 | color: new THREE.Color(this.environmentData.dressingColor) 982 | }); 983 | this.rendererSystem.applyColorCorrection(material.color); 984 | 985 | // create mesh 986 | var mesh = new THREE.Mesh(bufgeo, material); 987 | dressing.add(mesh); 988 | // add to scene 989 | this.dressing.setObject3D('mesh', dressing); 990 | }, 991 | 992 | // initializes the BufferGeometry for the stars 993 | createStars: function() { 994 | var numStars = 2000; 995 | var geometry = new THREE.BufferGeometry(); 996 | var positions = new Float32Array( numStars * 3 ); 997 | var radius = this.STAGE_SIZE - 1; 998 | var v = new THREE.Vector3(); 999 | for (var i = 0; i < positions.length; i += 3) { 1000 | v.set(this.random(i + 23) - 0.5, this.random(i + 24), this.random(i + 25) - 0.5); 1001 | v.normalize(); 1002 | v.multiplyScalar(radius); 1003 | positions[i ] = v.x; 1004 | positions[i+1] = v.y; 1005 | positions[i+2] = v.z; 1006 | } 1007 | geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); 1008 | geometry.setDrawRange(0, 0); // don't draw any yet 1009 | var material = new THREE.PointsMaterial({size: 0.01, color: 0xCCCCCC, fog: false}); 1010 | this.rendererSystem.applyColorCorrection(material.color); 1011 | this.stars.setObject3D('mesh', new THREE.Points(geometry, material)); 1012 | }, 1013 | 1014 | // removes and disposes the BufferGeometry of the stars 1015 | removeStars: function() { 1016 | if (!this.stars) return; 1017 | 1018 | var mesh = this.stars.getObject3D('mesh'); 1019 | mesh.material.dispose(); 1020 | mesh.geometry.dispose(); 1021 | 1022 | this.el.removeChild(this.stars); 1023 | this.stars = null; 1024 | }, 1025 | 1026 | // Sets the number of stars visible. Calls createStars() to initialize if needed. 1027 | setStars: function (numStars) { 1028 | numStars = Math.floor(Math.min(2000, Math.max(0, numStars))); 1029 | if (numStars === 0) { 1030 | this.removeStars(); 1031 | } else { 1032 | if (!this.stars) { 1033 | this.stars = document.createElement('a-entity'); 1034 | this.stars.id = 'stars'; 1035 | this.createStars(); 1036 | this.el.appendChild(this.stars); 1037 | } 1038 | this.stars.getObject3D('mesh').geometry.setDrawRange(0, numStars); 1039 | } 1040 | } 1041 | }); 1042 | 1043 | // atmosphere sky shader. From https://github.com/aframevr/aframe/blob/master/examples/test/shaders/shaders/sky.js 1044 | AFRAME.registerShader('skyshader', { 1045 | schema: { 1046 | exposureBias: { type: 'number', default: 1.0, min: 0, max: 10, is: 'uniform' }, 1047 | turbidity: { type: 'number', default: 2, min: 0, max: 20, is: 'uniform' }, 1048 | reileigh: { type: 'number', default: 1, min: 0, max: 4, is: 'uniform' }, 1049 | mieCoefficient: { type: 'number', default: 0.005, min: 0, max: 0.1, is: 'uniform' }, 1050 | mieDirectionalG: { type: 'number', default: 0.8, min: 0, max: 1, is: 'uniform' }, 1051 | sunPosition: { type: 'vec3', default: {x: 0, y: 0, z: -1}, is: 'uniform' }, 1052 | color: {type: 'color', default: '#fff'} //placeholder to remove warning 1053 | }, 1054 | 1055 | vertexShader: [ 1056 | 'varying vec3 vWorldPosition;', 1057 | 'void main() {', 1058 | 'vec4 worldPosition = modelMatrix * vec4( position, 1.0 );', 1059 | 'vWorldPosition = worldPosition.xyz;', 1060 | 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', 1061 | '}' 1062 | ].join('\n'), 1063 | 1064 | fragmentShader: [ 1065 | '#include ', 1066 | '#include ', 1067 | 'uniform sampler2D skySampler;', 1068 | 'uniform vec3 sunPosition;', 1069 | 'varying vec3 vWorldPosition;', 1070 | 1071 | 'vec3 cameraPos = vec3(0., 0., 0.);', 1072 | 1073 | 'uniform float exposureBias;', 1074 | 'uniform float turbidity;', 1075 | 'uniform float reileigh;', 1076 | 'uniform float mieCoefficient;', 1077 | 'uniform float mieDirectionalG;', 1078 | 1079 | // constants for atmospheric scattering' 1080 | 'const float e = 2.71828182845904523536028747135266249775724709369995957;', 1081 | 'const float pi = 3.141592653589793238462643383279502884197169;', 1082 | 1083 | // refractive index of air 1084 | 'const float n = 1.0003;', 1085 | // number of molecules per unit volume for air at' 1086 | 'const float N = 2.545E25;' , 1087 | // 288.15K and 1013mb (sea level -45 celsius) 1088 | // depolatization factor for standard air 1089 | 'const float pn = 0.035;', 1090 | // wavelength of used primaries, according to preetham 1091 | 'const vec3 lambda = vec3(680E-9, 550E-9, 450E-9);', 1092 | 1093 | // mie stuff 1094 | // K coefficient for the primaries 1095 | 'const vec3 K = vec3(0.686, 0.678, 0.666);', 1096 | 'const float v = 4.0;', 1097 | 1098 | // optical length at zenith for molecules 1099 | 'const float rayleighZenithLength = 8.4E3;', 1100 | 'const float mieZenithLength = 1.25E3;', 1101 | 'const vec3 up = vec3(0.0, 1.0, 0.0);', 1102 | 1103 | 'const float EE = 1000.0;', 1104 | 'const float sunAngularDiameterCos = 0.999956676946448443553574619906976478926848692873900859324;', 1105 | // 66 arc seconds -> degrees, and the cosine of that 1106 | 1107 | // earth shadow hack' 1108 | 'const float cutoffAngle = pi/1.95;', 1109 | 'const float steepness = 1.5;', 1110 | 1111 | 'vec3 totalRayleigh(vec3 lambda)', 1112 | '{', 1113 | 'return (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn));', 1114 | '}', 1115 | 1116 | // see http://blenderartists.org/forum/showthread.php?321110-Shaders-and-Skybox-madness 1117 | // A simplied version of the total Rayleigh scattering to works on browsers that use ANGLE 1118 | 'vec3 simplifiedRayleigh()', 1119 | '{', 1120 | 'return 0.0005 / vec3(94, 40, 18);', 1121 | '}', 1122 | 1123 | 'float rayleighPhase(float cosTheta)', 1124 | '{ ', 1125 | 'return (3.0 / (16.0*pi)) * (1.0 + pow(cosTheta, 2.0));', 1126 | '}', 1127 | 1128 | 'vec3 totalMie(vec3 lambda, vec3 K, float T)', 1129 | '{', 1130 | 'float c = (0.2 * T ) * 10E-18;', 1131 | 'return 0.434 * c * pi * pow((2.0 * pi) / lambda, vec3(v - 2.0)) * K;', 1132 | '}', 1133 | 1134 | 'float hgPhase(float cosTheta, float g)', 1135 | '{', 1136 | 'return (1.0 / (4.0*pi)) * ((1.0 - pow(g, 2.0)) / pow(1.0 - 2.0*g*cosTheta + pow(g, 2.0), 1.5));', 1137 | '}', 1138 | 1139 | 'float sunIntensity(float zenithAngleCos)', 1140 | '{', 1141 | 'return EE * max(0.0, 1.0 - exp(-((cutoffAngle - acos(zenithAngleCos))/steepness)));', 1142 | '}', 1143 | 1144 | '// Filmic ToneMapping http://filmicgames.com/archives/75', 1145 | 'float A = 0.15;', 1146 | 'float B = 0.50;', 1147 | 'float C = 0.10;', 1148 | 'float D = 0.20;', 1149 | 'float E = 0.02;', 1150 | 'float F = 0.30;', 1151 | 'float W = 1000.0;', 1152 | 1153 | 'vec3 Uncharted2Tonemap(vec3 x)', 1154 | '{', 1155 | 'return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;', 1156 | '}', 1157 | 1158 | 'void main() ', 1159 | '{', 1160 | 'float sunfade = 1.0-clamp(1.0-exp((sunPosition.y/450000.0)),0.0,1.0);', 1161 | 1162 | 'float reileighCoefficient = reileigh - (1.0* (1.0-sunfade));', 1163 | 1164 | 'vec3 sunDirection = normalize(sunPosition);', 1165 | 1166 | 'float sunE = sunIntensity(dot(sunDirection, up));', 1167 | 1168 | // extinction (absorbtion + out scattering) 1169 | // rayleigh coefficients 1170 | 1171 | 'vec3 betaR = simplifiedRayleigh() * reileighCoefficient;', 1172 | 1173 | // mie coefficients 1174 | 'vec3 betaM = totalMie(lambda, K, turbidity) * mieCoefficient;', 1175 | 1176 | // optical length 1177 | // cutoff angle at 90 to avoid singularity in next formula. 1178 | 'float zenithAngle = acos(max(0.0, dot(up, normalize(vWorldPosition - cameraPos))));', 1179 | 'float sR = rayleighZenithLength / (cos(zenithAngle) + 0.15 * pow(93.885 - ((zenithAngle * 180.0) / pi), -1.253));', 1180 | 'float sM = mieZenithLength / (cos(zenithAngle) + 0.15 * pow(93.885 - ((zenithAngle * 180.0) / pi), -1.253));', 1181 | 1182 | // combined extinction factor 1183 | 'vec3 Fex = exp(-(betaR * sR + betaM * sM));', 1184 | 1185 | // in scattering 1186 | 'float cosTheta = dot(normalize(vWorldPosition - cameraPos), sunDirection);', 1187 | 1188 | 'float rPhase = rayleighPhase(cosTheta*0.5+0.5);', 1189 | 'vec3 betaRTheta = betaR * rPhase;', 1190 | 1191 | 'float mPhase = hgPhase(cosTheta, mieDirectionalG);', 1192 | 'vec3 betaMTheta = betaM * mPhase;', 1193 | 1194 | 'vec3 Lin = pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * (1.0 - Fex),vec3(1.5));', 1195 | 'Lin *= mix(vec3(1.0),pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * Fex,vec3(1.0/2.0)),clamp(pow(1.0-dot(up, sunDirection),5.0),0.0,1.0));', 1196 | 1197 | //nightsky 1198 | 'vec3 direction = normalize(vWorldPosition - cameraPos);', 1199 | 'float theta = acos(direction.y); // elevation --> y-axis, [-pi/2, pi/2]', 1200 | 'float phi = atan(direction.z, direction.x); // azimuth --> x-axis [-pi/2, pi/2]', 1201 | 'vec2 uv = vec2(phi, theta) / vec2(2.0*pi, pi) + vec2(0.5, 0.0);', 1202 | // vec3 L0 = texture2D(skySampler, uv).rgb+0.1 * Fex; 1203 | 'vec3 L0 = vec3(0.1) * Fex;', 1204 | 1205 | // composition + solar disc 1206 | 'float sundisk = smoothstep(sunAngularDiameterCos,sunAngularDiameterCos+0.00002,cosTheta);', 1207 | 'L0 += (sunE * 19000.0 * Fex)*sundisk;', 1208 | 1209 | 'vec3 whiteScale = 1.0/Uncharted2Tonemap(vec3(W));', 1210 | 1211 | 'vec3 texColor = (Lin+L0);', 1212 | 'texColor *= 0.04;', 1213 | 'texColor += vec3(0.0,0.001,0.0025)*0.3;', 1214 | 1215 | 'vec3 curr = Uncharted2Tonemap(exposureBias*texColor);', 1216 | 'vec3 color = curr*whiteScale;', 1217 | 1218 | 'vec3 retColor = pow(color,vec3(1.0/(1.2+(1.2*sunfade))));', 1219 | 1220 | 'gl_FragColor.rgb = retColor;', 1221 | 1222 | 'gl_FragColor.a = 1.0;', 1223 | '#include ', 1224 | '}' 1225 | ].join('\n') 1226 | }); 1227 | 1228 | 1229 | // gradient sky shader 1230 | 1231 | AFRAME.registerShader('gradientshader', { 1232 | schema: { 1233 | topColor: {type: 'color', default: '1 0 0', is: 'uniform'}, 1234 | bottomColor: {type: 'color', default: '0 0 1', is: 'uniform'} 1235 | }, 1236 | 1237 | vertexShader: [ 1238 | 'varying vec3 vWorldPosition;', 1239 | 'void main() {', 1240 | ' vec4 worldPosition = modelMatrix * vec4( position, 1.0 );', 1241 | ' vWorldPosition = worldPosition.xyz;', 1242 | ' gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );', 1243 | '}' 1244 | ].join('\n'), 1245 | 1246 | fragmentShader: [ 1247 | '#include ', 1248 | '#include ', 1249 | 'uniform vec3 bottomColor;', 1250 | 'uniform vec3 topColor;', 1251 | 'uniform float offset;', 1252 | 'varying vec3 vWorldPosition;', 1253 | 'void main() {', 1254 | ' float h = normalize( vWorldPosition ).y;', 1255 | ' gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max(h, 0.0 ), 0.8 ), 0.0 ) ), 1.0 );', 1256 | ' #include ', 1257 | '}' 1258 | ].join('\n') 1259 | }); 1260 | 1261 | // perlin noise generator 1262 | // from https://gist.github.com/banksean/304522 1263 | 1264 | var PerlinNoise = function(seed) { 1265 | var randomWithSeed; 1266 | this.grad3 = [[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]]; 1267 | this.p = []; 1268 | var i; 1269 | for (i=0; i<256; i++) { 1270 | randomWithSeed = parseFloat('0.' + Math.sin(seed * 9999 * i).toString().substr(7)); 1271 | this.p[i] = Math.floor(randomWithSeed * 256); 1272 | } 1273 | // To remove the need for index wrapping, double the permutation table length 1274 | this.perm = []; 1275 | for(i=0; i<512; i++) { 1276 | this.perm[i]=this.p[i & 255]; 1277 | } 1278 | }; 1279 | 1280 | PerlinNoise.prototype.dot = function(g, x, y, z) { 1281 | return g[0]*x + g[1]*y + g[2]*z; 1282 | }; 1283 | 1284 | PerlinNoise.prototype.mix = function(a, b, t) { 1285 | return (1.0-t)*a + t*b; 1286 | }; 1287 | 1288 | PerlinNoise.prototype.fade = function(t) { 1289 | return t*t*t*(t*(t*6.0-15.0)+10.0); 1290 | }; 1291 | 1292 | // Classic Perlin noise, 3D version 1293 | PerlinNoise.prototype.noise = function(x, y, z) { 1294 | // Find unit grid cell containing point 1295 | var X = Math.floor(x); 1296 | var Y = Math.floor(y); 1297 | var Z = Math.floor(z); 1298 | 1299 | // Get relative xyz coordinates of point within that cell 1300 | x = x - X; 1301 | y = y - Y; 1302 | z = z - Z; 1303 | 1304 | // Wrap the integer cells at 255 (smaller integer period can be introduced here) 1305 | X = X & 255; 1306 | Y = Y & 255; 1307 | Z = Z & 255; 1308 | 1309 | // Calculate a set of eight hashed gradient indices 1310 | var gi000 = this.perm[X+this.perm[Y+this.perm[Z]]] % 12; 1311 | var gi001 = this.perm[X+this.perm[Y+this.perm[Z+1]]] % 12; 1312 | var gi010 = this.perm[X+this.perm[Y+1+this.perm[Z]]] % 12; 1313 | var gi011 = this.perm[X+this.perm[Y+1+this.perm[Z+1]]] % 12; 1314 | var gi100 = this.perm[X+1+this.perm[Y+this.perm[Z]]] % 12; 1315 | var gi101 = this.perm[X+1+this.perm[Y+this.perm[Z+1]]] % 12; 1316 | var gi110 = this.perm[X+1+this.perm[Y+1+this.perm[Z]]] % 12; 1317 | var gi111 = this.perm[X+1+this.perm[Y+1+this.perm[Z+1]]] % 12; 1318 | 1319 | // The gradients of each corner are now: 1320 | // g000 = grad3[gi000]; 1321 | // g001 = grad3[gi001]; 1322 | // g010 = grad3[gi010]; 1323 | // g011 = grad3[gi011]; 1324 | // g100 = grad3[gi100]; 1325 | // g101 = grad3[gi101]; 1326 | // g110 = grad3[gi110]; 1327 | // g111 = grad3[gi111]; 1328 | // Calculate noise contributions from each of the eight corners 1329 | var n000= this.dot(this.grad3[gi000], x, y, z); 1330 | var n100= this.dot(this.grad3[gi100], x-1, y, z); 1331 | var n010= this.dot(this.grad3[gi010], x, y-1, z); 1332 | var n110= this.dot(this.grad3[gi110], x-1, y-1, z); 1333 | var n001= this.dot(this.grad3[gi001], x, y, z-1); 1334 | var n101= this.dot(this.grad3[gi101], x-1, y, z-1); 1335 | var n011= this.dot(this.grad3[gi011], x, y-1, z-1); 1336 | var n111= this.dot(this.grad3[gi111], x-1, y-1, z-1); 1337 | // Compute the fade curve value for each of x, y, z 1338 | var u = this.fade(x); 1339 | var v = this.fade(y); 1340 | var w = this.fade(z); 1341 | // Interpolate along x the contributions from each of the corners 1342 | var nx00 = this.mix(n000, n100, u); 1343 | var nx01 = this.mix(n001, n101, u); 1344 | var nx10 = this.mix(n010, n110, u); 1345 | var nx11 = this.mix(n011, n111, u); 1346 | // Interpolate the four results along y 1347 | var nxy0 = this.mix(nx00, nx10, v); 1348 | var nxy1 = this.mix(nx01, nx11, v); 1349 | // Interpolate the two last results along z 1350 | var nxyz = this.mix(nxy0, nxy1, w); 1351 | 1352 | return nxyz; 1353 | }; 1354 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aframe-environment-component", 3 | "version": "1.5.0", 4 | "description": "Infinite environments for your A-Frame VR scene in just one file.", 5 | "main": "index.js", 6 | "cdn": "dist/aframe-environment-component.min.js", 7 | "scripts": { 8 | "dev": "budo index.js:dist/aframe-environment-component.min.js --port 7000 --live --open", 9 | "dist": "webpack index.js dist/aframe-environment-component.js && webpack -p index.js dist/aframe-environment-component.min.js", 10 | "lint": "semistandard -v | snazzy", 11 | "prepublish": "npm run dist", 12 | "ghpages": "ghpages", 13 | "start": "npm run dev", 14 | "test": "karma start ./tests/karma.conf.js", 15 | "test:firefox": "karma start ./tests/karma.conf.js --browsers Firefox", 16 | "test:chrome": "karma start ./tests/karma.conf.js --browsers Chrome" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/supermedium/aframe-environment-component.git" 21 | }, 22 | "keywords": [ 23 | "aframe", 24 | "aframe-component", 25 | "aframe-vr", 26 | "vr", 27 | "mozvr", 28 | "webvr", 29 | "environment" 30 | ], 31 | "author": "Diego F. Goberna ", 32 | "license": "MIT", 33 | "bugs": { 34 | "url": "https://github.com/supermedium/aframe-environment-component/issues" 35 | }, 36 | "homepage": "https://github.com/supermedium/aframe-environment-component#readme", 37 | "devDependencies": { 38 | "aframe": "*", 39 | "browserify": "^13.0.0", 40 | "budo": "^8.2.2", 41 | "chai": "^3.4.1", 42 | "chai-shallow-deep-equal": "^1.3.0", 43 | "ghpages": "^0.0.8", 44 | "karma": "^0.13.15", 45 | "karma-browserify": "^4.4.2", 46 | "karma-chai-shallow-deep-equal": "0.0.4", 47 | "karma-chrome-launcher": "2.0.0", 48 | "karma-env-preprocessor": "^0.1.1", 49 | "karma-firefox-launcher": "^0.1.7", 50 | "karma-mocha": "^0.2.1", 51 | "karma-mocha-reporter": "^1.1.3", 52 | "karma-sinon-chai": "^1.1.0", 53 | "mocha": "^2.3.4", 54 | "randomcolor": "^0.4.4", 55 | "semistandard": "^8.0.0", 56 | "shelljs": "^0.7.0", 57 | "sinon": "^1.17.5", 58 | "sinon-chai": "^2.8.0", 59 | "shx": "^0.1.1", 60 | "snazzy": "^4.0.0", 61 | "webpack": "^1.13.0" 62 | }, 63 | "semistandard": { 64 | "globals": [ 65 | "AFRAME", 66 | "THREE" 67 | ], 68 | "ignore": [ 69 | "examples/build.js", 70 | "dist/**" 71 | ] 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 53 | 54 | 55 |

Environment Component Tests

56 |
    57 |
  1. None
  2. 58 |
  3. preset:forest
  4. 59 |
  5. preset:forest; dressing:pyramids
  6. 60 |
  7. dressing:cubes; dressingAmount:20; dressingColor: #f88
  8. 61 |
62 |
63 | Params: 64 | 65 | 66 |
67 | 68 | 69 | 70 | 71 | 72 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /tools/extrudeEditor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ExtrudeGeometry Editor for ThreeJS 5 | 6 | 7 | 74 | 75 | 76 |
77 |
78 |

Extrude editor for three.js

79 |

80 | Place points on left canvas with Left Click
81 | Finish contour with Double Click, ENTER or ESC
82 | Delete / Add points by hovering on them and pressing DEL / INS
83 | Clear canvas with c key 84 |

85 |
86 | 87 | 88 |
89 | 92 |
93 | 94 | 403 | 404 | -------------------------------------------------------------------------------- /tools/latheEditor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LatheGeometry Editor for ThreeJS 5 | 6 | 7 | 74 | 75 | 76 |
77 |
78 |

Lathe editor for three.js

79 |

80 | Place points on left canvas with Left Click
81 | Finish contour with Double Click, ENTER or ESC
82 | Delete / Add points by hovering on them and pressing DEL / INS
83 | Clear canvas with c key 84 |

85 |
86 | 87 | 88 |
89 | 92 |
93 | 94 | 363 | 364 | --------------------------------------------------------------------------------