diff --git a/assets b/assets
index 25645ccd4..f724477b2 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit 25645ccd421a7e50682b0e5b4ebe3d22f667dcb3
+Subproject commit f724477b28e0867ca3dee08d1d6b11c2aafc2add
diff --git a/index.html b/index.html
index eed1f3516..af89e2629 100644
--- a/index.html
+++ b/index.html
@@ -14,7 +14,7 @@
-
+
@@ -70,6 +70,7 @@
notify
metadata
scene-title
+ reflection
>
diff --git a/src/aframe-streetmix-parsers.js b/src/aframe-streetmix-parsers.js
index 2cbf0526f..64fedba8c 100644
--- a/src/aframe-streetmix-parsers.js
+++ b/src/aframe-streetmix-parsers.js
@@ -108,22 +108,22 @@ function createStencilsParentElement (position) {
return placedObjectEl;
}
-function createRailsElement(length, railsPosX) {
+function createRailsElement (length, railsPosX) {
const placedObjectEl = document.createElement('a-entity');
const railsGeometry = {
- "primitive": "box",
- "depth": length,
- "width": 0.1,
- "height": 0.2,
+ primitive: 'box',
+ depth: length,
+ width: 0.1,
+ height: 0.2
- }
+ };
const railsMaterial = { // TODO: Add environment map for reflection on metal rails
- "color": "#8f8f8f",
- "metalness": 1,
- "emissive": "#828282",
- "emissiveIntensity": 0.5,
- "roughness": 0.1
- }
+ color: '#8f8f8f',
+ metalness: 1,
+ emissive: '#828282',
+ emissiveIntensity: 0.5,
+ roughness: 0.1
+ };
placedObjectEl.setAttribute('geometry', railsGeometry);
placedObjectEl.setAttribute('material', railsMaterial);
placedObjectEl.setAttribute('class', 'rails');
@@ -131,7 +131,6 @@ function createRailsElement(length, railsPosX) {
placedObjectEl.setAttribute('position', railsPosX + ' 0.2 0'); // position="1.043 0.100 -3.463"
return placedObjectEl;
-
}
function createTracksParentElement (length, objectMixinId) {
@@ -140,9 +139,9 @@ function createTracksParentElement (length, objectMixinId) {
placedObjectEl.setAttribute('position', '0 -0.2 0'); // position="1.043 0.100 -3.463"
// add rails
const railsWidth = { // width as measured from center of rail, so 1/2 actual width
- "tram": 0.7175, // standard gauge 1,435 mm
- "trolley": 0.5335 // sf cable car rail gauge 1,067 mm
- }
+ tram: 0.7175, // standard gauge 1,435 mm
+ trolley: 0.5335 // sf cable car rail gauge 1,067 mm
+ };
const railsPosX = railsWidth[objectMixinId];
placedObjectEl.append(createRailsElement(length, railsPosX));
placedObjectEl.append(createRailsElement(length, -railsPosX));
@@ -411,7 +410,7 @@ function createDriveLaneElement (variantList, segmentWidthInMeters, streetLength
mixin: 'self-driving-cruise-car-rig',
wheelDiameter: 0.76,
length: 5.17,
- width: 2
+ width: 2
}
};
@@ -1083,23 +1082,22 @@ function processSegments (segments, showStriping, length, globalAnimated, showVe
segmentParentEl.append(createSegmentElement(segmentWidthInMeters, positionY, groundMixinId, length, repeatCount, elevation));
} else {
segmentParentEl.append(createSeparatorElement(positionY, rotationY, groundMixinId, length, repeatCount, elevation));
-
}
// returns JSON output instead
// append the new surfaceElement to the segmentParentEl
streetParentEl.append(segmentParentEl);
segmentParentEl.setAttribute('position', segmentPositionX + ' 0 0');
- segmentParentEl.setAttribute('data-layer-name', 'Segment: ' + segments[i].type + ', ' + variantList[0])
+ segmentParentEl.setAttribute('data-layer-name', 'Segment: ' + segments[i].type + ', ' + variantList[0]);
}
// create new brown box to represent ground underneath street
- let dirtBox = document.createElement('a-box');
+ const dirtBox = document.createElement('a-box');
const xPos = cumulativeWidthInMeters / 2;
- console.log('xPos', xPos)
- console.log('`${xPos} -1.1 0`', `${xPos} -1.1 0`)
+ console.log('xPos', xPos);
+ console.log('`${xPos} -1.1 0`', `${xPos} -1.1 0`);
dirtBox.setAttribute('position', `${xPos} -1.1 0`); // what is x? x = 0 - cumulativeWidthInMeters / 2
- dirtBox.setAttribute('height', 2); // height is 2 meters from y of -0.1 to -y of 2.1
- dirtBox.setAttribute('width', cumulativeWidthInMeters);
- dirtBox.setAttribute('depth', length - 0.2); // depth is length - 0.1 on each side
+ dirtBox.setAttribute('height', 2); // height is 2 meters from y of -0.1 to -y of 2.1
+ dirtBox.setAttribute('width', cumulativeWidthInMeters);
+ dirtBox.setAttribute('depth', length - 0.2); // depth is length - 0.1 on each side
dirtBox.setAttribute('material', 'color: #664B00;');
dirtBox.setAttribute('data-layer-name', 'Underground');
streetParentEl.append(dirtBox);
@@ -1114,7 +1112,6 @@ function processBuildings (left, right, streetWidth, showGround, length) {
buildingElement.classList.add('buildings-parent');
buildingElement.setAttribute('data-layer-name', 'Buildings & Blocks Container');
buildingElement.setAttribute('position', '0 0.2 0');
- const buildingLotWidth = 150;
const buildingsArray = [left, right];
// TODO: Sound temporarily disabled
@@ -1134,24 +1131,58 @@ function processBuildings (left, right, streetWidth, showGround, length) {
return placedObjectEl;
}
- // possible 'block' type input values: grass, fence, narrow, wide, waterfront, residential, parking-lot
+ // possible 'block' type input values: grass, fence, narrow, wide, waterfront, residential, parking-lot, (new: archway, wall sp?)
buildingsArray.forEach((currentValue, index) => {
if (currentValue.length === 0) { return; } // if empty string then skip
const side = (index === 0) ? 'left' : 'right';
const sideMultiplier = (side === 'left') ? -1 : 1;
- const positionX = ((buildingLotWidth / 2) + (streetWidth / 2)) * sideMultiplier;
+ const groundPositionX = ((length / 4) + (streetWidth / 2)) * sideMultiplier;
+ const buildingPositionX = ((150 / 2) + (streetWidth / 2)) * sideMultiplier;
+ // this is the logic to make the ground box
if (showGround) {
- // TODO: consider rewriting this using simple box instead of this json plane method
- var groundJSONString = JSON.stringify(streetmixParsersTested.createGroundArray(currentValue, length));
+ const variantToMaterialMapping = {
+ grass: 'ground-grass-material',
+ fence: 'ground-grass-material',
+ 'parking-lot': 'ground-parking-lot-material',
+ residential: 'ground-grass-material',
+ narrow: 'ground-asphalt-material',
+ wide: 'ground-asphalt-material',
+ arcade: 'ground-tiled-concrete-material',
+ 'compound-wall': 'ground-asphalt-material'
+ }
+
+ if (currentValue === 'waterfront') {
+ var groundParentEl = document.createElement('a-ocean-box');
+ groundParentEl.setAttribute('geometry',
+ {
+ primitive: 'box',
+ depth: length,
+ width: length / 2,
+ height: 2,
+ segmentsHeight: 1,
+ segmentsDepth: 10,
+ segmentsWidth: 10
+ });
+ groundParentEl.setAttribute('position', { y: -3 });
+ } else {
+ var groundParentEl = document.createElement('a-box');
+ groundParentEl.setAttribute('depth', length);
+ groundParentEl.setAttribute('height', 2);
+ groundParentEl.setAttribute('width', length / 2);
+ groundParentEl.setAttribute('shadow', '');
+ // groundParentEl.setAttribute('material', 'src:#grass-texture;repeat:5 5;roughness:0.8;');
+ groundParentEl.setAttribute('mixin', variantToMaterialMapping[currentValue]); // case grass, fence
+ groundParentEl.setAttribute('position', { y: -1 });
+ }
+
- var groundParentEl = document.createElement('a-entity');
- groundParentEl.setAttribute('create-from-json', 'jsonString', groundJSONString);
if (side === 'right') {
- groundParentEl.setAttribute('position', positionX - 55 + ' 0.2 0');
+ // groundParentEl.setAttribute('position', groundPositionX + ' -1 0');
+ groundParentEl.setAttribute('position', { x: groundPositionX });
} else {
- groundParentEl.setAttribute('position', positionX + 55 + ' 0.2 0');
+ groundParentEl.setAttribute('position', { x: groundPositionX });
}
groundParentEl.classList.add('ground-' + side);
groundParentEl.setAttribute('data-layer-name', 'Ground ' + side + ': ' + currentValue);
@@ -1160,7 +1191,7 @@ function processBuildings (left, right, streetWidth, showGround, length) {
// make building
const buildingPos = {
- x: positionX,
+ x: buildingPositionX,
y: 0,
z: (index === 1) ? length / 2 : -length / 2
};
@@ -1179,32 +1210,38 @@ function processBuildings (left, right, streetWidth, showGround, length) {
case 'arcade':
buildingPos.x += sideMultiplier * (-70.5);
}
- let newBuildings = createBuilding(currentValue, sideMultiplier);
+ const newBuildings = createBuilding(currentValue, sideMultiplier);
newBuildings.setAttribute('data-layer-name', 'Buildings ' + side + ': ' + currentValue);
newBuildings.setAttribute('position', buildingPos);
buildingElement.append(newBuildings);
-
- if (currentValue === 'waterfront') {
- const objectPositionX = positionX - (sideMultiplier * buildingLotWidth / 2);
+ if (currentValue === 'waterfront' || currentValue === 'compound-wall') {
+ const objectPositionX = buildingPositionX - (sideMultiplier * 150 / 2);
const placedObjectEl = document.createElement('a-entity');
placedObjectEl.setAttribute('class', 'seawall-parent');
- placedObjectEl.setAttribute('position', objectPositionX + ' 0 0'); // position="1.043 0.100 -3.463"
+ placedObjectEl.setAttribute('position', {x: objectPositionX, z: 4.5}); // position="1.043 0.100 -3.463"
+ let rotationCloneY;
+ if (currentValue === 'compound-wall') {
+ placedObjectEl.setAttribute('position', {y: 3});
+ placedObjectEl.setAttribute('position', {x: objectPositionX + 1.5 * sideMultiplier});
+ rotationCloneY = (side === 'left') ? 90 : -90;
+ } else {
+ rotationCloneY = (side === 'left') ? -90 : 90;
+ }
placedObjectEl.classList.add('seawall-parent-' + side);
buildingElement.appendChild(placedObjectEl);
// clone a bunch of seawalls under the parent
- const rotationCloneY = (side === 'left') ? -90 : 90;
cloneMixinAsChildren({ objectMixinId: 'seawall', parentEl: placedObjectEl, rotation: '0 ' + rotationCloneY + ' 0', step: 15, radius: clonedObjectRadius });
}
if (currentValue === 'fence' || currentValue === 'parking-lot') {
- const objectPositionX = positionX - (sideMultiplier * buildingLotWidth / 2);
+ const objectPositionX = buildingPositionX - (sideMultiplier * 150 / 2);
// make the parent for all the objects to be cloned
const placedObjectEl = document.createElement('a-entity');
placedObjectEl.setAttribute('class', 'fence-parent');
placedObjectEl.setAttribute('position', objectPositionX + ' 0 4.625'); // position="1.043 0.100 -3.463"
- placedObjectEl.classList.add('fence-parent-' + positionX);
+ placedObjectEl.classList.add('fence-parent-' + buildingPositionX);
// clone a bunch of fences under the parent
const rotationCloneY = (side === 'right') ? -90 : 90;
cloneMixinAsChildren({ objectMixinId: 'fence', parentEl: placedObjectEl, rotation: '0 ' + rotationCloneY + ' 0', step: 9.25, radius: clonedObjectRadius });
diff --git a/src/assets.js b/src/assets.js
index 77ca5d316..1d1e3e101 100644
--- a/src/assets.js
+++ b/src/assets.js
@@ -214,13 +214,13 @@ function buildAssetHTML (assetUrl, categories) {
-
-
-
-
+
+
+
+
-
-
+
+
`,
'loud-bicycle': `
diff --git a/src/components/ocean-plane.js b/src/components/ocean-plane.js
deleted file mode 100644
index 0ac0717d1..000000000
--- a/src/components/ocean-plane.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/* global AFRAME */
-
-// from https://samsunginter.net/a-frame-components/dist/ocean-plane.js
-// Requires a build from the latest a-frame master (August 2016, v0.3)
-
-AFRAME.registerComponent('wobble-normal', {
- schema: {},
- tick: function (t) {
- if (!this.el.components.material.material.normalMap) return;
- this.el.components.material.material.normalMap.offset.x += 0.0001 * Math.sin(t / 10000);
- this.el.components.material.material.normalMap.offset.y += 0.0001 * Math.cos(t / 8000);
- this.el.components.material.material.normalScale.x = 0.5 + 0.5 * Math.cos(t / 1000);
- this.el.components.material.material.normalScale.x = 0.5 + 0.5 * Math.sin(t / 1200);
- }
-});
-
-AFRAME.registerPrimitive('a-ocean-plane', {
- defaultComponents: {
- geometry: {
- primitive: 'plane',
- height: 1000,
- width: 1000
- },
- rotation: '-90 0 0',
- material: {
- shader: 'standard',
- color: '#8ab39f',
- metalness: 1,
- roughness: 0.2,
- normalMap: 'url(assets/materials/waternormals.jpg)',
- normalTextureRepeat: '50 50',
- normalTextureOffset: '0 0',
- normalScale: '0.5 0.5',
- opacity: 0.8
- },
- 'wobble-normal': {}
- }
-});
diff --git a/src/components/ocean.js b/src/components/ocean.js
new file mode 100644
index 000000000..fde243544
--- /dev/null
+++ b/src/components/ocean.js
@@ -0,0 +1,149 @@
+/* global AFRAME */
+
+// from https://samsunginter.net/a-frame-components/dist/ocean-plane.js
+// Requires a build from the latest a-frame master (August 2016, v0.3)
+
+AFRAME.registerComponent('wobble-normal', {
+ schema: {},
+ tick: function (t) {
+ if (!this.el.components.material.material.normalMap) return;
+ this.el.components.material.material.normalMap.offset.x += 0.0001 * Math.sin(t / 10000);
+ this.el.components.material.material.normalMap.offset.y += 0.0001 * Math.cos(t / 8000);
+ this.el.components.material.material.normalScale.x = 0.5 + 0.5 * Math.cos(t / 1000);
+ this.el.components.material.material.normalScale.x = 0.5 + 0.5 * Math.sin(t / 1200);
+ }
+});
+
+AFRAME.registerComponent('wobble-geometry', {
+ schema: {
+ // Wave amplitude and variance.
+ amplitude: { default: 0.1 },
+ amplitudeVariance: { default: 0.3 },
+
+ // Wave speed and variance.
+ speed: { default: 0.25 },
+ speedVariance: { default: 2 }
+ },
+ play: function () {
+ const data = this.data;
+ const geometry = this.geometry = this.el.object3D.children[0].geometry;
+
+ console.log(this.el.object3D.children[0].geometry);
+ this.waves = [];
+ const posAttribute = geometry.getAttribute('position');
+ console.log(posAttribute);
+ for (let i = 0; i < posAttribute.count; i++) {
+ this.waves.push({
+ z: posAttribute.getZ(i),
+ ang: Math.random() * Math.PI * 2,
+ amp: data.amplitude + Math.random() * data.amplitudeVariance,
+ speed: (data.speed + Math.random() * data.speedVariance) / 1000 // radians / frame
+ });
+ }
+ },
+ tick: function (t, dt) {
+ if (!dt) return;
+
+ const posAttribute = this.geometry.getAttribute('position');
+ for (let i = 0; i < posAttribute.count; i++) {
+ const vprops = this.waves[i];
+ const value = vprops.z + Math.sin(vprops.ang) * vprops.amp;
+ posAttribute.setZ(i, value);
+ vprops.ang += vprops.speed * dt;
+ }
+ posAttribute.needsUpdate = true;
+ }
+});
+
+AFRAME.registerPrimitive('a-ocean-plane', {
+ defaultComponents: {
+ geometry: {
+ primitive: 'plane',
+ height: 1000,
+ width: 1000,
+ segmentsHeight: 100,
+ segmentsWidth: 100
+ },
+ rotation: '-90 0 0',
+ material: {
+ shader: 'standard',
+ color: '#8ab39f',
+ metalness: 1,
+ roughness: 0.2,
+ normalMap: 'url(assets/materials/waternormals.jpg)',
+ normalTextureRepeat: '50 50',
+ normalTextureOffset: '0 0',
+ normalScale: '0.5 0.5',
+ opacity: 0.8
+ },
+ 'wobble-normal': {},
+ 'wobble-geometry': {}
+ }
+});
+
+AFRAME.registerComponent('wobble-geometry-box', {
+ schema: {
+ // Wave amplitude and variance.
+ amplitude: { default: 0.1 },
+ amplitudeVariance: { default: 0.3 },
+
+ // Wave speed and variance.
+ speed: { default: 0.25 },
+ speedVariance: { default: 2 }
+ },
+ play: function () {
+ const data = this.data;
+ const geometry = this.geometry = this.el.object3D.children[0].geometry;
+
+ this.waves = [];
+ const posAttribute = geometry.getAttribute('position');
+ for (let i = 0; i < posAttribute.count; i++) {
+ this.waves.push({
+ y: posAttribute.getY(i),
+ ang: Math.random() * Math.PI * 2,
+ amp: data.amplitude + Math.random() * data.amplitudeVariance,
+ speed: (data.speed + Math.random() * data.speedVariance) / 1000 // radians / frame
+ });
+ }
+ },
+ tick: function (t, dt) {
+ if (!dt) return;
+
+ const posAttribute = this.geometry.getAttribute('position');
+ for (let i = 0; i < posAttribute.count; i++) {
+ const vprops = this.waves[i];
+ const value = vprops.y + Math.sin(vprops.ang) * vprops.amp;
+ posAttribute.setY(i, value);
+ vprops.ang += vprops.speed * dt;
+ }
+ posAttribute.needsUpdate = true;
+ }
+});
+
+AFRAME.registerPrimitive('a-ocean-box', {
+ defaultComponents: {
+ geometry: {
+ primitive: 'box',
+ depth: 100,
+ width: 100,
+ height: 4,
+ segmentsHeight: 10,
+ segmentsDepth: 100,
+ segmentsWidth: 100
+ },
+ rotation: '0 0 0',
+ material: {
+ shader: 'standard',
+ color: '#8ab39f',
+ metalness: 1,
+ roughness: 0.2,
+ normalMap: 'url(https://assets.3dstreet.app/materials/waternormals.jpg)',
+ normalTextureRepeat: '10 10',
+ normalTextureOffset: '0 0',
+ normalScale: '0.5 0.5',
+ opacity: 0.8
+ },
+ 'wobble-normal': {},
+ 'wobble-geometry-box': {}
+ }
+});
diff --git a/src/tested/aframe-streetmix-parsers-tested.js b/src/tested/aframe-streetmix-parsers-tested.js
index beb44a499..aff283b67 100644
--- a/src/tested/aframe-streetmix-parsers-tested.js
+++ b/src/tested/aframe-streetmix-parsers-tested.js
@@ -165,34 +165,3 @@ function getAmbientSoundJSON (buildingsArray) { // eslint-disable-line no-unused
return soundsArray;
}
module.exports.getAmbientSoundJSON = getAmbientSoundJSON;
-
-// possible input values: grass, fence, narrow, wide, waterfront, residential, parking-lot
-function createGroundArray (buildingString, length) { // eslint-disable-line no-unused-vars
- var repeatY = length / 30;
- var repeatX = 1;
- var groundArray = [];
- var mixin = 'ground-grass'; // default output is grass ground type
-
- if (buildingString === 'waterfront') { return groundArray; }
- if (['narrow', 'wide', 'arcade'].includes(buildingString)) { mixin = 'ground-asphalt'; }
- if (buildingString === 'parking-lot') {
- mixin = 'ground-parking-lot';
- repeatX = 0.5;
- }
- if (buildingString === 'arcade') {
- mixin = 'ground-tiled-concrete';
- repeatY = length / 2;
- repeatX = 20;
- }
- var groundEntity = {
- tag: 'a-entity',
- position: '0 -0.2 0',
- mixin: mixin,
- geometry: 'height: ' + length + ';',
- material: 'repeat: ' + repeatX + ' ' + repeatY + ';'
- };
- groundArray.push(groundEntity);
-
- return groundArray;
-}
-module.exports.createGroundArray = createGroundArray;
diff --git a/test/aframe-streetmix-parsers-test.js b/test/aframe-streetmix-parsers-test.js
index a598db812..7a65f02ef 100644
--- a/test/aframe-streetmix-parsers-test.js
+++ b/test/aframe-streetmix-parsers-test.js
@@ -53,33 +53,6 @@ describe('A-Frame Streetmix Parsers', function () {
});
});
- describe('#createGroundArray()', function () {
- it('createGroundArray("grass") should return array with one dictionary for a-entity with mixin ground-grass', function () {
- assert.deepStrictEqual(
- streetmixParsersTested.createGroundArray('grass', 150),
- [{ tag: 'a-entity', mixin: 'ground-grass', position: '0 -0.2 0', geometry: 'height: 150;', material: 'repeat: 1 5;' }]
- );
- });
- it('createGroundArray("parking-lot") should return array with one dictionary for a-entity with mixin ground-parking-lot', function () {
- assert.deepStrictEqual(
- streetmixParsersTested.createGroundArray('parking-lot', 150),
- [{ mixin: 'ground-parking-lot', position: '0 -0.2 0', tag: 'a-entity', geometry: 'height: 150;', material: 'repeat: 0.5 5;' }]
- );
- });
- it('createGroundArray("jiberish") should return array with one dictionary for a-entity with mixin ground-grass', function () {
- assert.deepStrictEqual(
- streetmixParsersTested.createGroundArray('jiberish', 75),
- [{ mixin: 'ground-grass', position: '0 -0.2 0', tag: 'a-entity', geometry: 'height: 75;', material: 'repeat: 1 2.5;' }]
- );
- });
- it('createGroundArray("narrow") should return array with one dictionary for a-entity with mixin ground-asphalt', function () {
- assert.deepStrictEqual(
- streetmixParsersTested.createGroundArray('narrow', 30),
- [{ mixin: 'ground-asphalt', position: '0 -0.2 0', tag: 'a-entity', geometry: 'height: 30;', material: 'repeat: 1 1;' }]
- );
- });
- });
-
describe('#getAmbientSoundJSON()', function () {
it('getAmbientSoundJSON(["narrow", "wide"]) should return array with one dictionary for a-entity with sound src #ambientmp3', function () {
assert.deepStrictEqual(