Skip to content

Commit

Permalink
WIP first person
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisgervang committed Jan 3, 2021
1 parent 9231432 commit 11c29a0
Show file tree
Hide file tree
Showing 4 changed files with 268 additions and 0 deletions.
203 changes: 203 additions & 0 deletions examples/first-person/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import React, {useState, useRef} from 'react';
import DeckGL from '@deck.gl/react';
import {TerrainLayer, TileLayer} from '@deck.gl/geo-layers';
import {useNextFrame, BasicControls, ResolutionGuide} from '@hubble.gl/react';
import {DeckAdapter, DeckScene, CameraKeyframes, LayerKeyframes} from '@hubble.gl/core';
import {easing} from 'popmotion';
import {FirstPersonView} from '@deck.gl/core';
import {BitmapLayer} from '@deck.gl/layers';
const INITIAL_VIEW_STATE = {
latitude: 46.24,
longitude: -122.18,
width: 640,
height: 480,
zoom: 11,
bearing: 0,
// pitch: 0,
position: [0, 0, 1000]
};

// Set your mapbox token here
const MAPBOX_TOKEN = process.env.MapboxAccessToken; // eslint-disable-line

const TERRAIN_IMAGE = `https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.png?access_token=${MAPBOX_TOKEN}`;
const SURFACE_IMAGE = `https://api.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}@2x.png?access_token=${MAPBOX_TOKEN}`;

// https://docs.mapbox.com/help/troubleshooting/access-elevation-data/#mapbox-terrain-rgb
// Note - the elevation rendered by this example is greatly exagerated!
const ELEVATION_DECODER = {
rScaler: 6553.6,
gScaler: 25.6,
bScaler: 0.1,
offset: -10000
};

const getCameraKeyframes = () => {
return new CameraKeyframes({
timings: [0, 6000],
keyframes: [
{
latitude: 46.24,
longitude: -122.18,
zoom: 11,
bearing: 0,
// pitch: 0,
width: 640,
height: 480,
position: [0, 0, 1000]
},
{
latitude: 46.24,
longitude: -122.18,
zoom: 11.5,
bearing: 0,
pitch: 60,
position: [0, 0, 2000]
}
],
easings: [easing.easeInOut]
});
};

const getKeyframes = () => {
return {
terrain: new LayerKeyframes({
layerId: 'terrain',
features: ['r', 'g', 'b'],
keyframes: [
{r: 255, g: 255, b: 255},
{r: 255, g: 0, b: 0},
{r: 255, g: 255, b: 0},
{r: 0, g: 255, b: 0},
{r: 0, g: 255, b: 255},
{r: 0, g: 0, b: 255},
{r: 255, g: 0, b: 255},
{r: 255, g: 255, b: 255}
],
timings: [0, 2000, 4000, 6000, 8000, 10000, 12000, 14000],
easings: [
easing.linear,
easing.linear,
easing.linear,
easing.linear,
easing.linear,
easing.linear,
easing.linear
]
})
};
};

/** @type {import('@hubble.gl/core/src/types').FrameEncoderSettings} */
const encoderSettings = {
framerate: 30,
webm: {
quality: 0.8
},
jpeg: {
quality: 0.8
},
gif: {
sampleInterval: 1000
}
};

export default function App() {
const deckgl = useRef(null);
const [ready, setReady] = useState(false);
const [busy, setBusy] = useState(false);
const [viewState, setViewState] = useState(INITIAL_VIEW_STATE);

const nextFrame = useNextFrame();
const [duration] = useState(15000);
const [rainbow, setRainbow] = useState(false);

const getDeckScene = animationLoop => {
return new DeckScene({
animationLoop,
lengthMs: duration,
width: 640,
height: 480,
initialKeyframes: getKeyframes()
});
};

const [adapter] = useState(new DeckAdapter(getDeckScene));

const getLayers = scene => {
const terrain = scene.keyframes.terrain.getFrame();
return [
new TerrainLayer({
id: 'terrain',
minZoom: 0,
maxZoom: 23,
strategy: 'no-overlap',
elevationDecoder: ELEVATION_DECODER,
elevationData: TERRAIN_IMAGE,
texture: rainbow ? null : SURFACE_IMAGE,
wireframe: false,
color: [terrain.r, terrain.g, terrain.b]
}),
new TileLayer({
data: SURFACE_IMAGE,

minZoom: 0,
maxZoom: 23,
tileSize: 256,

renderSubLayers: props => {
const {
bbox: {west, south, east, north}
} = props.tile;

return new BitmapLayer(props, {
data: null,
image: props.data,
bounds: [west, south, east, north]
});
}
})
];
};

return (
<div style={{position: 'relative'}}>
<div style={{position: 'absolute'}}>
<ResolutionGuide />
</div>
<DeckGL
ref={deckgl}
initialViewState={INITIAL_VIEW_STATE}
viewState={viewState}
views={new FirstPersonView({id: 'first-person', controller: true, far: 10000})}
onViewStateChange={({viewState: vs}) => {
setViewState(vs);
}}
controller={true}
parameters={{
depthTest: false,
clearColor: [135 / 255, 206 / 255, 235 / 255, 1]
}}
{...adapter.getProps(deckgl, setReady, nextFrame, getLayers)}
/>
<div style={{position: 'absolute'}}>
{ready && (
<BasicControls
adapter={adapter}
busy={busy}
setBusy={setBusy}
encoderSettings={encoderSettings}
getCameraKeyframes={getCameraKeyframes}
getKeyframes={getKeyframes}
/>
)}
<div style={{backgroundColor: 'rgba(255, 255, 255, 0.5)'}}>
<label style={{fontFamily: 'sans-serif'}}>
<input type="checkbox" checked={rainbow} onChange={() => setRainbow(!rainbow)} />
Rainbow Animation
</label>
</div>
</div>
</div>
);
}
6 changes: 6 additions & 0 deletions examples/first-person/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
import {render} from 'react-dom';
import App from './app';

document.body.style.backgroundColor = 'black';
render(<App />, document.body.appendChild(document.createElement('div')));
21 changes: 21 additions & 0 deletions examples/first-person/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"scripts": {
"start": "webpack-dev-server --progress --hot --open",
"start-local": "webpack-dev-server --env.local --progress --hot --open",
"clean": "rm -rf yarn.lock ./node_modules",
"bootstrap": "yarn clean && yarn"
},
"dependencies": {
},
"devDependencies": {
"@babel/core": "^7.12.1",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/preset-env": "^7.12.1",
"@babel/preset-react": "^7.12.1",
"babel-loader": "^8.0.5",
"html-webpack-plugin": "^3.0.7",
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.11"
}
}
38 changes: 38 additions & 0 deletions examples/first-person/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');

const config = {
mode: 'development',

entry: {
index: './index.js'
},

module: {
rules: [
{
// Transpile ES6 to ES5 with babel
// Remove if your app does not use JSX or you don't need to support old browsers
test: /\.js$/,
loader: 'babel-loader',
exclude: [/node_modules/],
options: {
plugins: ['@babel/plugin-proposal-class-properties'],
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
]
},

node: {
fs: 'empty'
},

plugins: [
new HtmlWebpackPlugin({title: 'hubble.gl terrain example'}),
// Optional: Enables reading mapbox token from environment variable
new webpack.EnvironmentPlugin(['MapboxAccessToken'])
]
};

module.exports = env => (env && env.local ? require('../webpack.config.local')(config) : config);

0 comments on commit 11c29a0

Please sign in to comment.