UNPKG

aframe-environment-component

Version:

Infinite environments for your A-Frame VR scene in just one file.

772 lines (681 loc) 70.6 kB
/* global AFRAME, THREE */ if (typeof AFRAME === 'undefined') { throw new Error('Component attempted to register before AFRAME was available.'); } AFRAME.registerComponent('environment', { schema: { active: {default: false}, 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: 1000}, skyType: {default: 'color', oneOf:['none', 'color', 'gradient', 'atmosphere']}, skyColor: {type: 'color'}, horizonColor: {type: 'color'}, lighting: {default: 'distant', oneOf: ['none', 'distant', 'point']}, shadow: {default: false}, shadowSize: { default: 10}, lightPosition: {type:'vec3', default: {x: 0, y: 1, z: -0.2}}, fog: {type:'float', default: 0, min: 0, max: 1}, flatShading: {default: false}, playArea: {type: 'float', default: 1, min: 0.5, max: 10}, stageSize: {type: 'number', default: 200, min: 1, max: 20000}, 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: 0.1, max: 1000}, dressing: {default: 'none', oneOf:['none', 'cubes', 'pyramids', 'cylinders', 'hexagons', 'stones', 'trees', 'mushrooms', 'towers', 'apparatus', 'arches', 'torii']}, dressingAmount: {type: 'int', default: 10, min: 0, max: 1000}, 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: true}, 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: false, presets: { 'none' : {}, '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}, '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}, '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}, '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}, '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}, '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}, '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}, '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}, '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}, '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}, '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}, '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}, '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}, '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}, '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}, '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}, '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}, '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} }, init: function () { this.environmentData = {}; // renderer system for color correction this.rendererSystem = this.el.sceneEl.systems.renderer; // stage ground diameter (and sky radius) this.STAGE_SIZE = this.data.stageSize; // data for dressing meshes 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: true, flatShading: true, 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: [-0.198, -0.302, 0.197, -0.3, 0.372, 0, 0.199, 0.298, -0.202, 0.298, -0.368, 0] } ], 'towers': [ {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]}, {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]}, {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]} ], 'trees': [ {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]}, {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]}, {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]} ], 'apparatus': [ {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]}, {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]}, ], 'mushrooms': [ {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]}, {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]}, {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]} ] }; // scale down dressing meshes (coordinates were saved in integers for better compression) for (var i in this.assets){ for (var j = 0; j < this.assets[i].length; j++) { var asset = this.assets[i][j]; if (asset.type != 'mesh') continue; for (var v = 0, len = asset.vertices.length; v < len; v++) { asset.vertices[v] /= 1000.0; } } } // save current scene fog this.userFog = this.el.sceneEl.getAttribute('fog'); // create sky this.sky = document.createElement('a-sky'); this.sky.setAttribute('radius', this.STAGE_SIZE); this.sky.setAttribute('theta-length', 110); this.sky.classList.add('environment'); // stars are created when needed this.stars = null; // create ground this.ground = document.createElement('a-entity'); this.ground.setAttribute('rotation', '-90 0 0'); this.ground.classList.add('environmentGround'); this.ground.classList.add('environment'); this.groundCanvas = null; this.groundTexture = null; this.groundMaterial = null; this.groundGeometry = null; this.dressing = document.createElement('a-entity'); this.dressing.classList.add('environmentDressing'); this.dressing.classList.add('environment'); this.gridCanvas = null; this.gridTexture = null; // create lights (one ambient hemisphere light, and one directional for the sun) this.hemilight = document.createElement('a-entity'); this.hemilight.classList.add('environment'); this.hemilight.setAttribute('position', '0 50 0'); this.hemilight.setAttribute('light', { type: 'hemisphere', color: '#CEE4F0', intensity: 1.256 }); this.sunlight = document.createElement('a-entity'); this.sunlight.classList.add('environment'); this.sunlight.setAttribute('position', this.data.lightPosition); this.sunlight.setAttribute('light', {intensity: 1.884}); // add everything to the scene this.el.appendChild(this.hemilight); this.el.appendChild(this.sunlight); this.el.appendChild(this.ground); this.el.appendChild(this.dressing); this.el.appendChild(this.sky); }, // returns a fog color from a specific sky type and sun height getFogColor: function (skyType, sunHeight) { // Note: linear operations are performed on the sRGB fog color // so tell Three that it's NoColorSpace and let it convert // to the working color space after all computations are done var fogColor; if (skyType == 'color' || skyType == 'none'){ fogColor = new THREE.Color().setStyle(this.environmentData.skyColor, THREE.NoColorSpace); } else if (skyType == 'gradient'){ fogColor = new THREE.Color().setStyle(this.environmentData.horizonColor, THREE.NoColorSpace); } else if (skyType == 'atmosphere') { var fogRatios = [ 1, 0.5, 0.22, 0.1, 0.05, 0]; var fogColors = ['#C0CDCF', '#81ADC5', '#525e62', '#2a2d2d', '#141616', '#000']; if (sunHeight <= 0) return '#000'; sunHeight = Math.min(1, sunHeight); for (var i = 0; i < fogRatios.length; i++){ if (sunHeight > fogRatios[i]) { var c1 = new THREE.Color().setStyle(fogColors[i - 1], THREE.NoColorSpace); var c2 = new THREE.Color().setStyle(fogColors[i], THREE.NoColorSpace); var a = (sunHeight - fogRatios[i]) / (fogRatios[i - 1] - fogRatios[i]); c2.lerp(c1, a); fogColor = c2; break; } } } // dim down the color fogColor.multiplyScalar(0.9); // mix it a bit with ground color fogColor.lerp(new THREE.Color().setStyle(this.data.groundColor, THREE.NoColorSpace), 0.3); // convert the resulting color to the working color space fogColor.setRGB(fogColor.r, fogColor.g, fogColor.b, THREE.SRGBColorSpace); return '#' + fogColor.getHexString(); }, update: function (oldDataNonPreset) { var oldData; if (!this.data.preset) { oldData = oldDataNonPreset; this.environmentData = this.data; } else { oldData = 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); } var skyType = this.environmentData.skyType; var sunPos = new THREE.Vector3(this.environmentData.lightPosition.x, this.environmentData.lightPosition.y, this.environmentData.lightPosition.z); sunPos.normalize(); // update light colors and intensities if (this.sunlight) { this.sunlight.setAttribute('position', this.environmentData.lightPosition); if (skyType != 'atmosphere') { // dim down the sky color for the light var skycol = new THREE.Color().setStyle(this.environmentData.skyColor, THREE.NoColorSpace); skycol.setRGB( (skycol.r + 1.0) / 2.0, (skycol.g + 1.0) / 2.0, (skycol.b + 1.0) / 2.0, THREE.SRGBColorSpace ); this.hemilight.setAttribute('light', { 'color': '#' + skycol.getHexString(), 'intensity': 1.884 }); this.sunlight.setAttribute('light', {'intensity': 1.884}); } else { this.hemilight.setAttribute('light', { 'color': '#CEE4F0', 'intensity': 0.314 + sunPos.y * 1.57 }); this.sunlight.setAttribute('light', {'intensity': 0.314 + sunPos.y * 1.57}); } 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 updateStageSize = this.environmentData.stageSize !== oldData.stageSize; if (updateStageSize) { this.STAGE_SIZE = this.data.stageSize; this.sky.setAttribute('radius', this.STAGE_SIZE); } // update sky colors if (skyType !== oldData.skyType || this.environmentData.skyColor != oldData.skyColor || this.environmentData.horizonColor != oldData.horizonColor) { var mat = {}; mat.shader = {'none': 'flat', 'color': 'flat', 'gradient': 'gradientshader', 'atmosphere': 'skyshader'}[skyType]; if (this.stars) { this.stars.setAttribute('visible', skyType == 'atmosphere'); } if (skyType == 'color') { mat.color = this.environmentData.skyColor; mat.fog = false; } else if (skyType == 'gradient') { // Gradient shader doesn't encode fragments, so pass in colors as NoColorSpace mat.topColor = new THREE.Color().setStyle(this.environmentData.skyColor, THREE.NoColorSpace); mat.bottomColor = new THREE.Color().setStyle(this.environmentData.horizonColor, THREE.NoColorSpace); } this.sky.setAttribute('material', mat); } // set atmosphere sun position and stars if (skyType == 'atmosphere') { this.sky.setAttribute('material', {'sunPosition': sunPos}); this.setStars((1 - Math.max(0, (sunPos.y + 0.08) * 8)) * 2000 ); } // set fog color if (this.environmentData.fog > 0) { this.el.sceneEl.setAttribute('fog', { color: this.getFogColor(skyType, sunPos.y), far: (1.01 - this.environmentData.fog) * this.STAGE_SIZE * 2 }); } else { this.el.sceneEl.removeAttribute('fog'); } // scene lights this.sunlight.setAttribute('light', {type: this.environmentData.lighting == 'point' ? 'point' : 'directional'}); this.sunlight.setAttribute('visible', this.environmentData.lighting !== 'none'); this.hemilight.setAttribute('visible', this.environmentData.lighting !== 'none'); // check if ground geometry needs to be calculated var updateGroundGeometry = !this.groundGeometry || this.environmentData.seed != oldData.seed || this.environmentData.ground != oldData.ground || this.environmentData.playArea != oldData.playArea || this.environmentData.flatShading != oldData.flatShading || this.environmentData.groundDensity != oldData.groundDensity || this.environmentData.groundFrequency != oldData.groundFrequency || updateStageSize; // check if any parameter of the ground was changed, and update it if (updateGroundGeometry || this.environmentData.groundColor != oldData.groundColor || this.environmentData.groundColor2 != oldData.groundColor2 || this.environmentData.groundYScale != oldData.groundYScale || this.environmentData.groundTexture != oldData.groundTexture || this.environmentData.gridColor != oldData.gridColor || this.environmentData.grid != oldData.grid ) { this.updateGround(updateGroundGeometry); // set bounce light color to ground color if (this.hemilight) this.hemilight.setAttribute('light', {'groundColor': this.environmentData.groundColor}); } // update dressing if (this.environmentData.seed != oldData.seed || this.environmentData.dressingOnPlayArea != oldData.dressingOnPlayArea || this.environmentData.dressing != oldData.dressing || this.environmentData.flatShading != oldData.flatShading || this.environmentData.dressingAmount != oldData.dressingAmount || this.environmentData.dressingScale != oldData.dressingScale || this.environmentData.dressingColor != oldData.dressingColor || this.environmentData.dressingVariance.x != oldData.dressingVariance.x || this.environmentData.dressingVariance.y != oldData.dressingVariance.y || this.environmentData.dressingVariance.z != oldData.dressingVariance.z || this.environmentData.dressingUniformScale != oldData.dressingUniformScale || updateStageSize ) { this.updateDressing(); } this.sky.setAttribute('visible', skyType !== 'none'); this.el.setAttribute('visible', this.environmentData.active); if (!this.environmentData.active) { if (this.userFog) { this.el.sceneEl.setAttribute('fog', this.userFog); } else { this.el.sceneEl.removeAttribute('fog'); } } // dump current component settings to console this.dumpParametersDiff(); }, remove: function() { if (this.userFog) { this.el.sceneEl.setAttribute('fog', this.userFog); } else { this.el.sceneEl.removeAttribute('fog'); } this.el.removeChild(this.hemilight); this.el.removeChild(this.sunlight); if (this.groundTexture) this.groundTexture.dispose(); if (this.gridTexture) this.gridTexture.dispose(); if (this.groundMaterial) this.groundMaterial.dispose(); if (this.groundGeometry) this.groundGeometry.dispose(); this.el.removeChild(this.ground); var dressingMesh = this.dressing.getObject3D('mesh'); if (dressingMesh && dressingMesh.children.length > 0) { dressingMesh.children[0].material.dispose(); dressingMesh.children[0].geometry.dispose(); } this.el.removeChild(this.dressing); this.el.removeChild(this.sky); this.removeStars(); }, // logs current parameters to console, for saving to a preset logPreset: function () { var str = '{'; for (var i in this.schema){ if (i == 'preset') continue; str += i + ': '; var type = this.schema[i].type; if (type == 'vec3') { str += '{ x: ' + this.environmentData[i].x + ', y: ' + this.environmentData[i].y + ', z: ' + this.environmentData[i].z + '}'; } else if (type == 'string' || type == 'color') { str += '"' + this.environmentData[i] + '"'; } else { str += this.environmentData[i]; } str += ', '; } str += '}'; console.log(str); }, // dumps current component settings to console. dumpParametersDiff: function () { // trim number to 3 decimals function dec3 (v) { return Math.floor(v * 1000) / 1000; } var params = []; var usingPreset = this.data.preset != 'none' ? this.presets[this.data.preset] : false; if (usingPreset) { params.push('preset: ' + this.data.preset); } for (var i in this.schema) { if (i == 'preset' || (usingPreset && usingPreset[i] === undefined)) { continue; } var def = usingPreset ? usingPreset[i] : this.schema[i].default; var data = this.environmentData[i]; var type = this.schema[i].type; if (type == 'vec3') { var coords = def; if (typeof(def) == 'string') { def = def.split(' '); coords = {x: def[0], y: def[1], z: def[2]}; } if (dec3(coords.x) != dec3(data.x) || dec3(coords.y) != dec3(data.y) || dec3(coords.z) != dec3(data.z)) { params.push(i + ': ' + dec3(data.x) + ' ' + dec3(data.y) + ' ' + dec3(data.z)); } } else { if (def != data) { if (this.schema[i].type == 'number') { data = dec3(data); } params.push(i + ': ' + data); } } } console.log('%c' + params.join('; '), 'color: #f48;font-weight:bold'); }, // Custom Math.random() with seed. Given this.environmentData.seed and x, it always returns the same "random" number random: function (x) { return parseFloat('0.' + Math.sin(this.environmentData.seed * 9999 * x).toString().substr(7)); }, // updates ground attributes, and geometry if required updateGround: function (updateGeometry) { var resolution = this.environmentData.groundDensity; // number of divisions of the ground mesh if (updateGeometry) { var visibleground = this.environmentData.ground != 'none'; this.ground.setAttribute('visible', visibleground); if (!visibleground) { return; } if (!this.groundGeometry) { this.groundGeometry = new THREE.PlaneGeometry(this.STAGE_SIZE + 2, this.STAGE_SIZE + 2, resolution - 1, resolution - 1); } var perlin = new PerlinNoise(this.environmentData.seed); var verts = this.groundGeometry.attributes.position.array; var numVerts = verts.length; var frequency = this.environmentData.groundFrequency; var inc = frequency / resolution; var x = 0; var y = 0; for (var i = 2; i < numVerts; i+=3) { if (this.environmentData.ground == 'flat') { verts[i] = 0; continue; } var h; switch (this.environmentData.ground) { case 'hills': { h = Math.max(0, perlin.noise(x, y, 0)); break; } case 'canyon': { h = 0.2 + perlin.noise(x, y, 0) * 0.8; h = Math.min(1, Math.pow(h, 2) * 10); break; } case 'spikes': { h = this.random(i) < 0.02 ? this.random(i + 1) : 0; break; } case 'noise': { h = this.random(i) < 0.35 ? this.random(i + 1) : 0; break; } } h += this.random(i + 2) * 0.1; // add some randomness // flat ground in the center var xx = x * 2 / frequency - 1; var yy = y * 2 / frequency - 1; var pa = this.environmentData.playArea; xx = Math.max(0, Math.min(1, (Math.abs(xx) - (pa - 0.9)) * (1 / pa) )); yy = Math.max(0, Math.min(1, (Math.abs(yy) - (pa - 0.9)) * (1 / pa) )); h *= xx > yy ? xx : yy; if (h < 0.01) h = 0; // stick to the floor // set height verts[i] = h; // calculate next x,y ground coordinates x += inc; if (x >= frequency) { x = 0; y += inc; } } this.groundGeometry.computeVertexNormals(); this.groundGeometry.attributes.position.needsUpdate = true; this.groundGeometry.attributes.normal.needsUpdate = true; } // apply Y scale. There's no need to recalculate the geometry for this. Just change scale this.ground.setAttribute('scale', {z: this.environmentData.groundYScale}); // update ground, playarea and grid textures. var groundResolution = 2048; var texMeters = 20; // ground texture of 20 x 20 meters var texRepeat = this.STAGE_SIZE / texMeters; if (!this.groundCanvas || this.groundCanvas.width != groundResolution) { this.gridCanvas = document.createElement('canvas'); this.gridCanvas.width = groundResolution; this.gridCanvas.height = groundResolution; this.gridTexture = new THREE.Texture(this.gridCanvas); this.gridTexture.wrapS = THREE.RepeatWrapping; this.gridTexture.wrapT = THREE.RepeatWrapping; this.gridTexture.repeat.set(texRepeat, texRepeat); this.gridTexture.anisotropy = 4; this.rendererSystem.applyColorCorrection(this.gridTexture); this.groundCanvas = document.createElement('canvas'); this.groundCanvas.width = groundResolution; this.groundCanvas.height = groundResolution; this.groundTexture = new THREE.Texture(this.groundCanvas); this.groundTexture.wrapS = THREE.RepeatWrapping; this.groundTexture.wrapT = THREE.RepeatWrapping; this.groundTexture.repeat.set(texRepeat, texRepeat); this.groundTexture.anisotropy = 4; this.rendererSystem.applyColorCorrection(this.groundTexture); // ground material diffuse map is the regular ground texture and the grid texture // is used in the emissive map. This way, the grid is always equally visible, even at night. this.groundMaterialProps = { map: this.groundTexture, emissive: new THREE.Color(0xFFFFFF), emissiveMap: this.gridTexture }; this.groundMaterialProps.flatShading = this.environmentData.flatShading; this.groundMaterial = new THREE.MeshLambertMaterial(this.groundMaterialProps); } var groundctx = this.groundCanvas.getContext('2d'); var gridctx = this.gridCanvas.getContext('2d'); this.drawTexture(groundctx, groundResolution, texMeters); gridctx.fillStyle = '#000000'; gridctx.fillRect(0, 0, groundResolution, groundResolution); this.drawGrid(gridctx, groundResolution, texMeters); this.groundTexture.needsUpdate = true; this.gridTexture.needsUpdate = true; if (updateGeometry) { var mesh = new THREE.Mesh(this.groundGeometry, this.groundMaterial); this.ground.setObject3D('mesh', mesh); } else { this.ground.getObject3D('mesh').material = this.groundMaterial; } this.ground.setAttribute('shadow', { cast: false, receive: this.environmentData.shadow }); }, // draw grid to a canvas context drawGrid: function (ctx, size, texMeters) { if (this.environmentData.grid == 'none') return; // one grid feature each 2 meters var num = Math.floor(texMeters / 2); var step = size / (texMeters / 2); // 2 meters == <step> pixels var i, j, ii; ctx.fillStyle = this.environmentData.gridColor; switch (this.environmentData.grid) { case '1x1': case '2x2': { if (this.environmentData.grid == '1x1') { num = num * 2; step = size / texMeters; } for (i = 0; i < num; i++) { ii = Math.floor(i * step); ctx.fillRect(0, ii, size, 1); ctx.fillRect(ii, 0, 1, size); } break; } case 'crosses': { var l = Math.floor(step / 20); for (i = 0; i < num + 1; i++) { ii = Math.floor(i * step); for (j = 0; j < num + 1; j++) { var jj = Math.floor(-l + j * step); ctx.fillRect(jj, ii, l * 2, 1); ctx.fillRect(ii, jj, 1, l * 2); } } break; } case 'dots': { for (i = 0; i < num + 1; i++) { for (j = 0; j < num + 1; j++) { ctx.beginPath(); ctx.arc(Math.floor(j * step), Math.floor(i * step), 4, 0, Math.PI * 2); ctx.fill(); } } break; } case 'xlines': { for (i = 0; i < num; i++) { ctx.fillRect(Math.floor(i * step), 0, 1, size); } break; } case 'ylines': { for (i = 0; i < num; i++) { ctx.fillRect(0, Math.floor(i * step), size, 1); } break; } } }, // draw ground texture to a canvas context drawTexture: function(ctx, size, texMeters) { // fill all with ground Color ctx.fillStyle = this.environmentData.groundColor; ctx.fillRect(0, 0, size, size); var i, col, col1, col2, im, imdata, numpixels; if (this.environmentData.groundTexture == 'none') return; switch(this.environmentData.groundTexture) { case 'checkerboard': { ctx.fillStyle = this.environmentData.groundColor2; var num = Math.floor(texMeters / 2); var step = size / (texMeters / 2); // 2 meters == <step> pixels for (i = 0; i < num + 1; i += 2) { for (var j = 0; j < num + 1; j ++) { ctx.fillRect(Math.floor((i + j % 2) * step), Math.floor(j * step), Math.floor(step), Math.floor(step)); } } break; } case 'squares': { var numSquares = 16; var squareSize = size / numSquares; // Note: use THREE.NoColorSpace to perform operations on sRGB colors directly col1 = new THREE.Color().setStyle(this.environmentData.groundColor, THREE.NoColorSpace); col2 = new THREE.Color().setStyle(this.environmentData.groundColor2, THREE.NoColorSpace); for (i = 0; i < numSquares * numSquares; i++) { col = this.random(i + 3) > 0.5 ? col1.clone() : col2.clone(); col.addScalar(this.random(i + 3) * 0.1 - 0.05); ctx.fillStyle = '#' + col.getHexString(THREE.NoColorSpace); ctx.fillRect((i % numSquares) * squareSize, Math.floor(i / numSquares) * squareSize, squareSize, squareSize); } break; } case 'noise': { // TODO: fix imdata = ctx.getImageData(0, 0, size, size); im = imdata.data; // Note: use THREE.NoColorSpace to perform operations on sRGB colors directly col1 = new THREE.Color().setStyle(this.environmentData.groundColor, THREE.NoColorSpace); col2 = new THREE.Color().setStyle(this.environmentData.groundColor2, THREE.NoColorSpace); var diff = new THREE.Color(col2.r - col1.r, col2.g - col1.g, col2.b - col1.b); var perlin = new PerlinNoise(); for (i = 0, j = 0, numpixels = im.length; i < numpixels; i += 4, j++){ var rnd = perlin.noise((j % size) / size * 3, j / size / size * 3, 0); im[i + 0] = Math.floor((col1.r + diff.r * rnd) * 255); im[i + 1] = Math.floor((col1.g + diff.g * rnd) * 255); im[i + 2] = Math.floor((col1.b + diff.b * rnd) * 255); } ctx.putImageData(imdata, 0, 0); break; } case 'walkernoise': { var s = Math.floor(siz