Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP First Person #63

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);