aframe-shader-buildings
Version:
An A-Frame WebVR component for cheaply creating thousands of boxy buildings.
217 lines (197 loc) • 12.3 kB
HTML
<html>
<head>
<meta charset="UTF-8">
<title>aframe-shader-buildings example</title>
<meta name="description" content="A low-cost VR city, using aframe-shader-buildings">
<script src="https://aframe.io/releases/1.4.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@fb96ab2/dist/aframe-extras.controls.min.js"></script>
<script src="dist/main.js"></script>
<script src="https://unpkg.com/aframe-simple-sun-sky@^1.2.3/simple-sun-sky.js"></script>
<script>
AFRAME.registerComponent('city', {
init: function () {
let sceneEl = this.el;
const numStyles = 6;
let buildings = this.randomBuildings(numStyles); // array of arrays
let buildingEls = new Array(numStyles);
buildingEls[0] = document.createElement('a-shader-buildings');
buildingEls[0].setAttribute('wall-src', '#brick');
buildingEls[0].setAttribute('wall-color', '#6e2b11'); // brick red
buildingEls[0].setAttribute('px', '#px');
buildingEls[0].setAttribute('nx', '#nx');
buildingEls[0].setAttribute('py', '#py');
buildingEls[0].setAttribute('ny', '#ny');
buildingEls[0].setAttribute('nz', '#nz');
buildingEls[0].setAttribute('window-opacity', '0.2');
buildingEls[1] = document.createElement('a-shader-buildings');
buildingEls[1].setAttribute('x-proportion-geometry', 4);
buildingEls[1].setAttribute('x-proportion-material', 4);
buildingEls[1].setAttribute('z-proportion-geometry', 4);
buildingEls[1].setAttribute('z-proportion-material', 4);
buildingEls[1].setAttribute('y-proportion-geometry', 3.5);
buildingEls[1].setAttribute('y-proportion-material', 3.5);
buildingEls[1].setAttribute('window-width', -0.5);
buildingEls[1].setAttribute('window-height', 0.0);
buildingEls[1].setAttribute('wall-src', '#brick');
buildingEls[1].setAttribute('wall-zoom', 2.25);
buildingEls[1].setAttribute('wall-color', '#6e2b11'); // brick red
buildingEls[1].setAttribute('window-opacity', '0.9');
buildingEls[2] = document.createElement('a-shader-buildings');
buildingEls[2].setAttribute('x-proportion-geometry', 6);
buildingEls[2].setAttribute('x-proportion-material', 6);
buildingEls[2].setAttribute('z-proportion-geometry', 6);
buildingEls[2].setAttribute('z-proportion-material', 6);
buildingEls[2].setAttribute('y-proportion-geometry', 4.5);
buildingEls[2].setAttribute('y-proportion-material', 4.5);
buildingEls[2].setAttribute('window-width', -0.5);
buildingEls[2].setAttribute('window-height', 0.3);
buildingEls[2].setAttribute('wall-src', '#concrete');
buildingEls[2].setAttribute('wall-zoom', 1.5);
buildingEls[2].setAttribute('wall-color', '#a0a0a0'); // light gray
buildingEls[2].setAttribute('px', '#px');
buildingEls[2].setAttribute('nx', '#nx');
buildingEls[2].setAttribute('py', '#py');
buildingEls[2].setAttribute('ny', '#ny');
buildingEls[2].setAttribute('nz', '#nz');
buildingEls[2].setAttribute('window-opacity', '0.3');
buildingEls[3] = document.createElement('a-shader-buildings');
buildingEls[3].setAttribute('x-proportion-geometry', 6);
buildingEls[3].setAttribute('x-proportion-material', 6);
buildingEls[3].setAttribute('z-proportion-geometry', 6);
buildingEls[3].setAttribute('z-proportion-material', 6);
buildingEls[3].setAttribute('y-proportion-geometry', 5.5);
buildingEls[3].setAttribute('y-proportion-material', 5.5);
buildingEls[3].setAttribute('window-width', 0.95);
buildingEls[3].setAttribute('window-height', 0.0);
buildingEls[3].setAttribute('wall-src', '#concreteBlocks');
buildingEls[3].setAttribute('wall-zoom', 3.0);
buildingEls[3].setAttribute('wall-color', '#a0a0a0'); // light gray
buildingEls[3].setAttribute('equirectangular', '#equirectangular');
buildingEls[3].setAttribute('window-opacity', '0.8');
buildingEls[4] = document.createElement('a-shader-buildings');
buildingEls[4].setAttribute('y-proportion-geometry', 5);
buildingEls[4].setAttribute('y-proportion-material', 5);
buildingEls[4].setAttribute('window-width', 0.5);
buildingEls[4].setAttribute('window-height', 0.0);
buildingEls[4].setAttribute('wall-src', '#stoneBlocks');
buildingEls[4].setAttribute('wall-zoom', 4.5);
buildingEls[4].setAttribute('wall-color', '#909090'); // light gray
buildingEls[4].setAttribute('px', '#px');
buildingEls[4].setAttribute('nx', '#nx');
buildingEls[4].setAttribute('py', '#py');
buildingEls[4].setAttribute('ny', '#ny');
buildingEls[4].setAttribute('nz', '#nz');
buildingEls[4].setAttribute('window-opacity', '0.4');
buildingEls[5] = document.createElement('a-shader-buildings');
buildingEls[5].setAttribute('window-width', 0.8);
buildingEls[5].setAttribute('window-height', -0.1);
buildingEls[5].setAttribute('wall-src', '#stoneBlocks');
buildingEls[5].setAttribute('wall-zoom', 5.0);
buildingEls[5].setAttribute('wall-color', '#675342'); // brown brick
buildingEls[5].setAttribute('equirectangular', '#equirectangular');
buildingEls[5].setAttribute('window-opacity', '0.7');
for (let s=0; s<numStyles; ++s) {
buildingEls[s].setAttribute('elevation-geometry', 10);
buildingEls[s].setAttribute('elevation-material', 10);
buildingEls[s].setAttribute('sun-position', "-0.3 1.0 0.7");
buildingEls[s].setAttribute('buildings', JSON.stringify(buildings[s]));
buildingEls[s].classList.add('landscape');
sceneEl.appendChild(buildingEls[s]);
}
},
randomBuildings: function (numStyles) {
let buildings = new Array(numStyles);
for (let s=0; s<numStyles; ++s) {
buildings[s] = [];
}
for (let i=-15.5; i<=15.5; ++i) {
for (let j = -15.5; j <= 15.5; ++j) {
let xCoreSections = 1 + Math.floor(Math.random() * 4);
let xWingSections = Math.floor(Math.random() * 4);
let zCoreSections = 1 + Math.floor(Math.random() * 4);
let zWingSections = Math.floor(Math.random() * 4);
let ySections = Math.ceil((Math.exp(Math.random()) - 0.99999) * 20) + Math.random() * 0.2;
// sanity-checks proportions
if (xWingSections >= 2 && zCoreSections < 2) {
++zCoreSections
}
if (zWingSections >= 2 && xCoreSections < 2) {
++xCoreSections
}
if (ySections >= 2) {
while (xCoreSections + xWingSections < 2) {
++xCoreSections;
}
while (zCoreSections + zWingSections < 2) {
++zCoreSections;
}
}
if (ySections >= 10) {
while (zCoreSections + zWingSections < 3) {
++zCoreSections;
}
}
if (ySections >= 20) {
while (xCoreSections + xWingSections < 3) {
++xCoreSections;
}
}
let building = {
x: i * 60, // common multiple of x-proportion for building styles
z: j * 60, // common multiple of z-proportion for building styles
xCoreSections: xCoreSections,
xWingSections: xWingSections,
zCoreSections: zCoreSections,
zWingSections: zWingSections,
ySections: ySections,
};
let style = Math.floor(Math.random() * numStyles);
if (0 === style % 2) {
// makes some walls blank (only works if windowWidth is not too great)
if (zCoreSections <= 2 && Math.random() < 0.3) {
building.xWingSections += 0.13;
} else if (xCoreSections <= 2 && Math.random() < 0.3) {
building.zWingSections += 0.13;
} else if (zCoreSections + zWingSections <= 4.5 && Math.random() < 0.1) {
building.xCoreSections += 0.13;
} else if (xCoreSections + xWingSections <= 4.5 && Math.random() < 0.1) {
building.zCoreSections += 0.13;
}
}
buildings[style].push(building);
}
}
return buildings;
}
});
</script>
</head>
<body>
<a-scene city gridhelperXXX="size: 2000; divisions: 400" background="color:#87cefa">
<a-assets>
<img id="brick" src="./assets/TexturesCom_Wall_BrickPlain1_512_albedo.jpg">
<img id="concrete" src="./assets/TexturesCom_Concrete_ExposedAggregate_512_albedo.jpg">
<img id="concreteBlocks" src="./assets/TexturesCom_ConcreteBlocks_New_512_albedo.jpg">
<img id="stoneBlocks" src="./assets/TexturesCom_BrickMedievalBlocks0327_5_seamless_S_512.jpeg">
<img id="equirectangular" src="assets/reading_room_1k.jpg">
<img id="px" src="assets/MarriottMadisonWest/px.jpg">
<img id="nx" src="assets/MarriottMadisonWest/nx.jpg">
<img id="py" src="assets/MarriottMadisonWest/py.jpg">
<img id="ny" src="assets/MarriottMadisonWest/ny.jpg">
<img id="nz" src="assets/MarriottMadisonWest/nz.jpg">
</a-assets>
<a-plane position="0 9.95 0" rotation="-90 0 0" width="2000" height="2000" color="#276B48"></a-plane>
<!-- The "Burj Synthetica" -->
<a-shader-buildings window-opacity="0.9" elevation-geometry="10" elevation-material="10" sun-position="-0.3 1.0 0.7" buildings=
'[{"x":5,"z":-995,"xCoreSections":7,"xWingSections":5,"zCoreSections":7,"zWingSections":5,"ySections":30},{"x":0,"z":-1000,"y":120,"xCoreSections":5,"xWingSections":4,"zCoreSections":5,"zWingSections":4,"ySections":30},{"x":-5,"z":-1005,"y":240,"xCoreSections":3,"xWingSections":3,"zCoreSections":3,"zWingSections":3,"ySections":30},{"x":-5,"z":-1005,"y":360,"xCoreSections":2,"xWingSections":1,"zCoreSections":2,"zWingSections":1,"ySections":30}]'
></a-shader-buildings>
<a-entity id="rig" movement-controls="fly:true; speed:0.9;" position="0 32 0">
<a-entity camera look-controls position="0 1.6 0"></a-entity>
</a-entity>
<a-simple-sun-sky radius="1500" sun-position="-0.3 1.0 0.7"></a-simple-sun-sky>
<a-entity light="type: ambient; color: #BBB"></a-entity>
<a-entity light="type: directional; color: #FFF; intensity: 0.6" position="-0.3 1.0 0.7"></a-entity>
</a-scene>
</body>
</html>